diff options
Diffstat (limited to 'stm/i2c.c')
-rw-r--r-- | stm/i2c.c | 364 |
1 files changed, 0 insertions, 364 deletions
diff --git a/stm/i2c.c b/stm/i2c.c deleted file mode 100644 index 011362cb5b..0000000000 --- a/stm/i2c.c +++ /dev/null @@ -1,364 +0,0 @@ -#include <stdio.h> - -#include <stm32f4xx.h> - -#include "misc.h" -#include "systick.h" -#include "mpconfig.h" -#include "qstr.h" -#include "obj.h" - -typedef enum { - PYB_I2C_1 = 0, - PYB_I2C_2 = 1, -} pyb_i2c_t; - -typedef enum { - I2C_STATE_IDLE = 0, - I2C_STATE_WRITE = 1, - I2C_STATE_READ = 2, -} i2c_state_t; - -// set to true if the port has already been initialized -bool i2c1_port_initialized = false; -bool i2c2_port_initialized = false; - -static I2C_TypeDef * _i2c_port_addr(pyb_i2c_t i2c_port) { - if (i2c_port == PYB_I2C_1) { - return I2C1; - } - if (i2c_port == PYB_I2C_2) { - return I2C2; - } - return NULL; -} - -// todo - perhaps there should be some global resource management for gpio -// this function would fail if the i2c pins have already been defined for -// use by another python object -// as it is, this always returns true (unless i2c_port is invalid) -static bool _i2c_init(pyb_i2c_t i2c_port) { - GPIO_InitTypeDef GPIO_InitStructure; - - I2C_TypeDef *i2c = _i2c_port_addr(i2c_port); - if (i2c == NULL) - return false; - - if (i2c_port == PYB_I2C_1) { - if (i2c1_port_initialized == true) { - return true; - } - RCC->APB1ENR |= RCC_APB1ENR_I2C1EN; // enable I2C1 - - // PB6=SCL, PB7=SDA - GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7; - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; - GPIO_InitStructure.GPIO_OType = GPIO_OType_OD; - GPIO_InitStructure.GPIO_Speed = GPIO_Speed_25MHz; - GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; - GPIO_Init(GPIOB, &GPIO_InitStructure); - - // alternate functions for SCL and SDA - GPIO_PinAFConfig(GPIOB, GPIO_PinSource6, GPIO_AF_I2C1); - GPIO_PinAFConfig(GPIOB, GPIO_PinSource7, GPIO_AF_I2C1); - - - i2c1_port_initialized = true; - } - - if (i2c_port == PYB_I2C_2) { - if (i2c2_port_initialized == true) { - return true; - } - RCC->APB1ENR |= RCC_APB1ENR_I2C2EN; // enable I2C2 - - // PB10=SCL, PB11=SDA - GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10 | GPIO_Pin_11; - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; - GPIO_InitStructure.GPIO_OType = GPIO_OType_OD; - GPIO_InitStructure.GPIO_Speed = GPIO_Speed_25MHz; - GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; - GPIO_Init(GPIOB, &GPIO_InitStructure); - - // alternate functions for SCL and SDA - GPIO_PinAFConfig(GPIOB, GPIO_PinSource10, GPIO_AF_I2C2); - GPIO_PinAFConfig(GPIOB, GPIO_PinSource11, GPIO_AF_I2C2); - - i2c2_port_initialized = true; - } - - // get clock speeds - RCC_ClocksTypeDef rcc_clocks; - RCC_GetClocksFreq(&rcc_clocks); - - // disable the I2C peripheral before we configure it - i2c->CR1 &= ~I2C_CR1_PE; - - // program peripheral input clock - i2c->CR2 = 4; // no interrupts; 4 MHz (hopefully!) (could go up to 42MHz) - - // configure clock control reg - uint32_t freq = rcc_clocks.PCLK1_Frequency / (100000 << 1); // want 100kHz, this is the formula for freq - i2c->CCR = freq; // standard mode (speed), freq calculated as above - - // configure rise time reg - i2c->TRISE = (rcc_clocks.PCLK1_Frequency / 1000000) + 1; // formula for trise, gives maximum rise time - - // enable the I2C peripheral - i2c->CR1 |= I2C_CR1_PE; - - return true; -} - -static uint32_t _i2c_get_sr(pyb_i2c_t i2c_port) { - // must read SR1 first, then SR2, as the read can clear some flags - I2C_TypeDef *i2c = _i2c_port_addr(i2c_port); - if (i2c == NULL) return 0; - - uint32_t sr1 = i2c->SR1; - uint32_t sr2 = i2c->SR2; - return (sr2 << 16) | sr1; -} - -static bool _i2c_restart(pyb_i2c_t i2c_port, uint8_t addr, int write) { - I2C_TypeDef *i2c = _i2c_port_addr(i2c_port); - if (i2c == NULL) return false; - - // send start condition - i2c->CR1 |= I2C_CR1_START; - - // wait for BUSY, MSL and SB --> Slave has acknowledged start condition - uint32_t timeout = 1000000; - while ((_i2c_get_sr(i2c_port) & 0x00030001) != 0x00030001) { - if (--timeout == 0) { - //printf("timeout in _i2c_restart\n"); - return false; - } - } - - if (write) { - // send address and write bit - i2c->DR = (addr << 1) | 0; - // wait for BUSY, MSL, ADDR, TXE and TRA - timeout = 1000000; - while ((_i2c_get_sr(i2c_port) & 0x00070082) != 0x00070082) { - if (--timeout == 0) { - //printf("timeout in _i2c_restart write\n"); - return false; - } - } - } else { - // send address and read bit - i2c->DR = (addr << 1) | 1; - // wait for BUSY, MSL and ADDR flags - timeout = 1000000; - while ((_i2c_get_sr(i2c_port) & 0x00030002) != 0x00030002) { - if (--timeout == 0) { - //printf("timeout in _i2c_restart read\n"); - return false; - } - } - } - return true; -} - -static bool _i2c_send_byte(pyb_i2c_t i2c_port, uint8_t data) { - I2C_TypeDef *i2c = _i2c_port_addr(i2c_port); - if (i2c == NULL) return false; - - // send byte - i2c->DR = data; - // wait for TRA, BUSY, MSL, TXE and BTF (byte transmitted) - uint32_t timeout = 1000000; - while ((_i2c_get_sr(i2c_port) & 0x00070084) != 0x00070084) { - if (--timeout == 0) { - //printf("timeout in _i2c_send_byte\n"); - return false; - } - } - return true; -} - -static uint8_t _i2c_read_ack(pyb_i2c_t i2c_port) { - I2C_TypeDef *i2c = _i2c_port_addr(i2c_port); - if (i2c == NULL) return 0; - - // enable ACK of received byte - i2c->CR1 |= I2C_CR1_ACK; - // wait for BUSY, MSL and RXNE (byte received) - uint32_t timeout = 1000000; - while ((_i2c_get_sr(i2c_port) & 0x00030040) != 0x00030040) { - if (--timeout == 0) { - //printf("timeout in _i2c_read_ack\n"); - break; - } - } - // read and return data - uint8_t data = i2c->DR; - return data; -} - -static uint8_t _i2c_read_nack(pyb_i2c_t i2c_port) { - I2C_TypeDef *i2c = _i2c_port_addr(i2c_port); - if (i2c == NULL) return 0; - - // disable ACK of received byte (to indicate end of receiving) - i2c->CR1 &= (uint16_t)~((uint16_t)I2C_CR1_ACK); - // last byte should apparently also generate a stop condition - i2c->CR1 |= I2C_CR1_STOP; - // wait for BUSY, MSL and RXNE (byte received) - uint32_t timeout = 1000000; - while ((_i2c_get_sr(i2c_port) & 0x00030040) != 0x00030040) { - if (--timeout == 0) { - //printf("timeout in _i2c_read_nack\n"); - break; - } - } - // read and return data - uint8_t data = i2c->DR; - return data; -} - -static bool _i2c_start(pyb_i2c_t i2c_port) { - I2C_TypeDef *i2c = _i2c_port_addr(i2c_port); - if (i2c == NULL) return false; - - // wait until I2C is not busy - uint32_t timeout = 1000000; - while (i2c->SR2 & I2C_SR2_BUSY) { - if (--timeout == 0) { - return false; - } - } - return true; -} - -static void _i2c_stop(pyb_i2c_t i2c_port) { - I2C_TypeDef *i2c = _i2c_port_addr(i2c_port); - if (i2c == NULL) return; - - // send stop condition - i2c->CR1 |= I2C_CR1_STOP; -} - -/******************************************************************************/ -/* Micro Python bindings */ - -typedef struct _pyb_i2c_obj_t { - mp_obj_base_t base; - pyb_i2c_t i2c_port; - int i2c_addr; - i2c_state_t i2c_state; -} pyb_i2c_obj_t; - -void i2c_obj_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) { - pyb_i2c_obj_t *self = self_in; - print(env, "<I2C%lu addr:%lu>", (unsigned int)self->i2c_port, (unsigned int)self->i2c_addr); -} - -// calls _i2c_start with write=0,1 depending on LSB of i2c_addr -mp_obj_t i2c_obj_start(mp_obj_t self_in) { - pyb_i2c_obj_t *self = self_in; - if (self->i2c_state != I2C_STATE_IDLE) { - _i2c_stop(self->i2c_port); - self->i2c_state = I2C_STATE_IDLE; - } - if (_i2c_start(self->i2c_port) == true) - return mp_const_true; - return mp_const_false; -} - -mp_obj_t i2c_obj_write(mp_obj_t self_in, mp_obj_t data_in) { - pyb_i2c_obj_t *self = self_in; - if (self->i2c_state != I2C_STATE_WRITE) { - if (_i2c_restart(self->i2c_port, self->i2c_addr, 1) == false) { - _i2c_stop(self->i2c_port); - self->i2c_state = I2C_STATE_IDLE; - return mp_const_false; - } - self->i2c_state = I2C_STATE_WRITE; - } - uint8_t data = mp_obj_get_int(data_in); - if (_i2c_send_byte(self->i2c_port, data) == false) - return mp_const_false; - return mp_const_true; -} - -mp_obj_t i2c_obj_read(mp_obj_t self_in) { - pyb_i2c_obj_t *self = self_in; - if (self->i2c_state != I2C_STATE_READ) { - if (_i2c_restart(self->i2c_port, self->i2c_addr, 0) == false) { - _i2c_stop(self->i2c_port); - self->i2c_state = I2C_STATE_IDLE; - return mp_const_false; - } - self->i2c_state = I2C_STATE_READ; - } - uint8_t data = _i2c_read_ack(self->i2c_port); - return mp_obj_new_int(data); -} - -mp_obj_t i2c_obj_readAndStop(mp_obj_t self_in) { - pyb_i2c_obj_t *self = self_in; - if (self->i2c_state != I2C_STATE_READ) { - if (_i2c_restart(self->i2c_port, self->i2c_addr, 0) == false) { - _i2c_stop(self->i2c_port); - self->i2c_state = I2C_STATE_IDLE; - return mp_const_false; - } - } - uint8_t data = _i2c_read_nack(self->i2c_port); - self->i2c_state = I2C_STATE_IDLE; - return mp_obj_new_int(data); -} - -mp_obj_t i2c_obj_stop(mp_obj_t self_in) { - pyb_i2c_obj_t *self = self_in; - _i2c_stop(self->i2c_port); - self->i2c_state = I2C_STATE_IDLE; - return mp_const_none; -} - -static MP_DEFINE_CONST_FUN_OBJ_1(i2c_obj_start_obj, i2c_obj_start); -static MP_DEFINE_CONST_FUN_OBJ_2(i2c_obj_write_obj, i2c_obj_write); -static MP_DEFINE_CONST_FUN_OBJ_1(i2c_obj_read_obj, i2c_obj_read); -static MP_DEFINE_CONST_FUN_OBJ_1(i2c_obj_readAndStop_obj, i2c_obj_readAndStop); -static MP_DEFINE_CONST_FUN_OBJ_1(i2c_obj_stop_obj, i2c_obj_stop); - -STATIC const mp_map_elem_t i2c_locals_dict_table[] = { - { MP_OBJ_NEW_QSTR(MP_QSTR_start), (mp_obj_t)&i2c_obj_start_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_write), (mp_obj_t)&i2c_obj_write_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_read), (mp_obj_t)&i2c_obj_read_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_readAndStop), (mp_obj_t)&i2c_obj_readAndStop_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_stop), (mp_obj_t)&i2c_obj_stop_obj }, -}; - -STATIC MP_DEFINE_CONST_DICT(i2c_locals_dict, i2c_locals_dict_table); - -static const mp_obj_type_t i2c_obj_type = { - { &mp_type_type }, - .name = MP_QSTR_I2C, - .print = i2c_obj_print, - .locals_dict = (mp_obj_t)&i2c_locals_dict, -}; - -// create the I2C object -// currently support either I2C1 (i2c_id = 0) or I2C2 (i2c_id = 1) - -mp_obj_t pyb_I2C(mp_obj_t i2c_id, mp_obj_t i2c_addr) { - pyb_i2c_t i2c_port; - switch(mp_obj_get_int(i2c_id)) { - case 0: i2c_port = PYB_I2C_1; break; - case 1: i2c_port = PYB_I2C_2; break; - default: return mp_const_none; - } - if (_i2c_init(i2c_port) == false) { - return mp_const_none; - } - pyb_i2c_obj_t *o = m_new_obj(pyb_i2c_obj_t); - o->base.type = &i2c_obj_type; - o->i2c_port = i2c_port; - o->i2c_addr = mp_obj_get_int(i2c_addr); - o->i2c_state = I2C_STATE_IDLE; - return o; -} |