i2c slave block transfer driver library
Dependents: i2c_slave_block_example i2c_lora_slave
I2C block read/write slave
operates with I2C master using the i2c_smbus_read_i2c_block_data() and i2c_smbus_write_i2c_block_data() calls.
Tested with raspberry pi as master.
STM32Lx nucleo as slave.
signal pin | mbed slave | RPi master |
---|---|---|
GND | 6 | |
SCL | D15 | 5 |
SDA | D14 | 3 |
IRQ | any avail pin | any avail pin |
IRQ pin is implemented in application, not in this library. (see example)
Up to 32byte length per transfer.
Raspberry pi I2C doesnt support SMBUS block read, so I2C block transfers are supported here.
SMBUS block transfers are variable length.
Instead, here in this driver, I2C block length is mapped to command byte by const array cmd_to_length[]
(see example)
master write to slave
For i2c_smbus_write_i2c_block_data()
from master, this driver lets the main loop on slave take the write request. The main loop on slave calls service_i2c()
, which then calls service_i2c_write()
upon each write from master. This occurs thru a circular buffer, permitting the slave to take its time doing the request, while the master can issue several back-to-back requests without delays.
clock stretching
For i2c_smbus_read_i2c_block_data()
: Since raspberry pi doesnt support clock stretching out the the box, providing transmit data must be done in the interrupt service routine. fill_tx_buf()
populates the transmit buffer to be sent to master, which must be done immediately because this occurs inside interrupt handler.
If I2C master were to support clock stretching, then transmit buffer work could be done in main loop of slave.
An STM32 running at 32MHz is unlikely to operate with 400KHz I2C. Use 100KHz speed with 32MHz CPU, or use faster speed CPU for 400KHz I2C.
TARGET_STM/smbus.c@5:493e5cc9c052, 2019-02-04 (annotated)
- Committer:
- Wayne Roberts
- Date:
- Mon Feb 04 13:42:05 2019 -0800
- Revision:
- 5:493e5cc9c052
- Parent:
- 4:7ab789db70da
update HAL state for STM32L4
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
Wayne Roberts |
3:c012313ebc13 | 1 | #include "hal/pinmap.h" |
Wayne Roberts |
3:c012313ebc13 | 2 | #include "PeripheralPins.h" |
Wayne Roberts |
3:c012313ebc13 | 3 | #include "i2c_device.h" |
Wayne Roberts |
0:20421a857bd5 | 4 | #include "smbus.h" |
Wayne Roberts |
3:c012313ebc13 | 5 | #include "mbed_interface.h" // mbed_error_printf |
Wayne Roberts |
0:20421a857bd5 | 6 | |
Wayne Roberts |
0:20421a857bd5 | 7 | i2c_slave_t i2c; |
Wayne Roberts |
0:20421a857bd5 | 8 | |
Wayne Roberts |
3:c012313ebc13 | 9 | static DMA_HandleTypeDef hdma_tx; |
Wayne Roberts |
3:c012313ebc13 | 10 | static DMA_HandleTypeDef hdma_rx; |
Wayne Roberts |
3:c012313ebc13 | 11 | static SMBUS_HandleTypeDef SmbusHandle; |
Wayne Roberts |
3:c012313ebc13 | 12 | static IRQn_Type event_i2cIRQ; |
Wayne Roberts |
3:c012313ebc13 | 13 | static IRQn_Type error_i2cIRQ; |
Wayne Roberts |
3:c012313ebc13 | 14 | |
Wayne Roberts |
0:20421a857bd5 | 15 | static inline void put_cbuf(uint8_t o) |
Wayne Roberts |
0:20421a857bd5 | 16 | { |
Wayne Roberts |
0:20421a857bd5 | 17 | i2c.cbuf[i2c.cbuf_in] = o; |
Wayne Roberts |
3:c012313ebc13 | 18 | if (++i2c.cbuf_in == CBUF_SIZE) |
Wayne Roberts |
0:20421a857bd5 | 19 | i2c.cbuf_in = 0; |
Wayne Roberts |
3:c012313ebc13 | 20 | |
Wayne Roberts |
3:c012313ebc13 | 21 | if (i2c.cbuf_in == i2c.cbuf_out) { |
Wayne Roberts |
3:c012313ebc13 | 22 | i2c.c_overrun = true; |
Wayne Roberts |
3:c012313ebc13 | 23 | } |
Wayne Roberts |
0:20421a857bd5 | 24 | } |
Wayne Roberts |
0:20421a857bd5 | 25 | |
Wayne Roberts |
3:c012313ebc13 | 26 | static inline void err_irqHandler(uint32_t tmpisrvalue) |
Wayne Roberts |
3:c012313ebc13 | 27 | { |
Wayne Roberts |
3:c012313ebc13 | 28 | uint32_t _icr = 0; |
Wayne Roberts |
3:c012313ebc13 | 29 | if (tmpisrvalue & SMBUS_FLAG_BERR) { |
Wayne Roberts |
3:c012313ebc13 | 30 | put_cbuf(CMD_BUSERR); |
Wayne Roberts |
3:c012313ebc13 | 31 | put_cbuf(1); |
Wayne Roberts |
3:c012313ebc13 | 32 | put_cbuf(hdma_tx.Instance->CNDTR); // req[0] |
Wayne Roberts |
3:c012313ebc13 | 33 | |
Wayne Roberts |
3:c012313ebc13 | 34 | _icr |= SMBUS_FLAG_BERR; |
Wayne Roberts |
3:c012313ebc13 | 35 | } |
Wayne Roberts |
3:c012313ebc13 | 36 | |
Wayne Roberts |
3:c012313ebc13 | 37 | if (tmpisrvalue & SMBUS_FLAG_ARLO) { |
Wayne Roberts |
3:c012313ebc13 | 38 | put_cbuf(CMD_ARLO); |
Wayne Roberts |
3:c012313ebc13 | 39 | put_cbuf(1); |
Wayne Roberts |
3:c012313ebc13 | 40 | put_cbuf(hdma_tx.Instance->CNDTR); // req[0] |
Wayne Roberts |
3:c012313ebc13 | 41 | |
Wayne Roberts |
3:c012313ebc13 | 42 | _icr |= SMBUS_FLAG_ARLO; |
Wayne Roberts |
3:c012313ebc13 | 43 | } |
Wayne Roberts |
3:c012313ebc13 | 44 | |
Wayne Roberts |
3:c012313ebc13 | 45 | if (tmpisrvalue & SMBUS_FLAG_TIMEOUT) { |
Wayne Roberts |
3:c012313ebc13 | 46 | SmbusHandle.Instance->CR1 &= ~I2C_CR1_TXDMAEN; |
Wayne Roberts |
3:c012313ebc13 | 47 | __HAL_DMA_DISABLE(&hdma_tx); |
Wayne Roberts |
3:c012313ebc13 | 48 | __HAL_UNLOCK(&hdma_tx); |
Wayne Roberts |
5:493e5cc9c052 | 49 | hdma_tx.State = HAL_DMA_STATE_READY; |
Wayne Roberts |
3:c012313ebc13 | 50 | |
Wayne Roberts |
3:c012313ebc13 | 51 | SmbusHandle.Instance->CR1 &= ~I2C_CR1_RXDMAEN; |
Wayne Roberts |
3:c012313ebc13 | 52 | __HAL_DMA_DISABLE(&hdma_rx); |
Wayne Roberts |
3:c012313ebc13 | 53 | __HAL_UNLOCK(&hdma_rx); |
Wayne Roberts |
5:493e5cc9c052 | 54 | hdma_rx.State = HAL_DMA_STATE_READY; |
Wayne Roberts |
3:c012313ebc13 | 55 | |
Wayne Roberts |
3:c012313ebc13 | 56 | put_cbuf(CMD_TIMEOUT); |
Wayne Roberts |
3:c012313ebc13 | 57 | put_cbuf(1); |
Wayne Roberts |
3:c012313ebc13 | 58 | put_cbuf(hdma_tx.Instance->CNDTR); // req[0] |
Wayne Roberts |
5:493e5cc9c052 | 59 | |
Wayne Roberts |
3:c012313ebc13 | 60 | _icr |= SMBUS_FLAG_TIMEOUT; |
Wayne Roberts |
3:c012313ebc13 | 61 | } |
Wayne Roberts |
3:c012313ebc13 | 62 | |
Wayne Roberts |
3:c012313ebc13 | 63 | __HAL_SMBUS_CLEAR_FLAG(&SmbusHandle, _icr); |
Wayne Roberts |
3:c012313ebc13 | 64 | } |
Wayne Roberts |
0:20421a857bd5 | 65 | |
Wayne Roberts |
0:20421a857bd5 | 66 | #ifdef TARGET_STM32L4 |
Wayne Roberts |
0:20421a857bd5 | 67 | void SMBUSx_ER_IRQHandler() |
Wayne Roberts |
0:20421a857bd5 | 68 | { |
Wayne Roberts |
3:c012313ebc13 | 69 | err_irqHandler(SMBUS_GET_ISR_REG(&SmbusHandle)); |
Wayne Roberts |
0:20421a857bd5 | 70 | } |
Wayne Roberts |
0:20421a857bd5 | 71 | |
Wayne Roberts |
0:20421a857bd5 | 72 | void SMBUSx_EV_IRQHandler(void) |
Wayne Roberts |
0:20421a857bd5 | 73 | #else |
Wayne Roberts |
0:20421a857bd5 | 74 | void SMBUSx_IRQHandler(void) |
Wayne Roberts |
0:20421a857bd5 | 75 | #endif |
Wayne Roberts |
0:20421a857bd5 | 76 | { |
Wayne Roberts |
0:20421a857bd5 | 77 | uint32_t tmpisrvalue = SMBUS_GET_ISR_REG(&SmbusHandle); |
Wayne Roberts |
0:20421a857bd5 | 78 | uint32_t icr = 0; |
Wayne Roberts |
3:c012313ebc13 | 79 | |
Wayne Roberts |
0:20421a857bd5 | 80 | static bool i2cTransferDirection; // true = read |
Wayne Roberts |
3:c012313ebc13 | 81 | static bool stopWaiting = false; |
Wayne Roberts |
3:c012313ebc13 | 82 | |
Wayne Roberts |
3:c012313ebc13 | 83 | static uint8_t _rx_buf[33]; // [0] is cmd |
Wayne Roberts |
0:20421a857bd5 | 84 | |
Wayne Roberts |
3:c012313ebc13 | 85 | /* often multiple flags are set simultaneously, yet must still be taken in correct order */ |
Wayne Roberts |
0:20421a857bd5 | 86 | |
Wayne Roberts |
3:c012313ebc13 | 87 | #ifdef DEBUG_SMBUS |
Wayne Roberts |
3:c012313ebc13 | 88 | put_cbuf(CMD_ISR); |
Wayne Roberts |
3:c012313ebc13 | 89 | put_cbuf(1); |
Wayne Roberts |
3:c012313ebc13 | 90 | put_cbuf(tmpisrvalue & 0xff); |
Wayne Roberts |
3:c012313ebc13 | 91 | #endif /* DEBUG_SMBUS */ |
Wayne Roberts |
0:20421a857bd5 | 92 | |
Wayne Roberts |
0:20421a857bd5 | 93 | if (tmpisrvalue & SMBUS_FLAG_ADDR) { |
Wayne Roberts |
0:20421a857bd5 | 94 | i2cTransferDirection = SMBUS_GET_DIR(&SmbusHandle); |
Wayne Roberts |
3:c012313ebc13 | 95 | if (i2cTransferDirection) { // if host read |
Wayne Roberts |
0:20421a857bd5 | 96 | // 1: Read transfer, slave enters transmitter mode.. cmd has already been provided |
Wayne Roberts |
5:493e5cc9c052 | 97 | |
Wayne Roberts |
3:c012313ebc13 | 98 | SmbusHandle.Instance->CR1 &= ~I2C_CR1_RXDMAEN; |
Wayne Roberts |
3:c012313ebc13 | 99 | __HAL_DMA_DISABLE(&hdma_rx); |
Wayne Roberts |
3:c012313ebc13 | 100 | __HAL_UNLOCK(&hdma_rx); |
Wayne Roberts |
5:493e5cc9c052 | 101 | hdma_rx.State = HAL_DMA_STATE_READY; |
Wayne Roberts |
5:493e5cc9c052 | 102 | #ifdef TARGET_STM32L4 |
Wayne Roberts |
5:493e5cc9c052 | 103 | // clear dma interrupt flags |
Wayne Roberts |
5:493e5cc9c052 | 104 | hdma_rx.DmaBaseAddress->IFCR = (DMA_ISR_GIF1 << hdma_rx.ChannelIndex); |
Wayne Roberts |
5:493e5cc9c052 | 105 | #endif |
Wayne Roberts |
3:c012313ebc13 | 106 | |
Wayne Roberts |
3:c012313ebc13 | 107 | fill_tx_buf(_rx_buf[0]); |
Wayne Roberts |
0:20421a857bd5 | 108 | |
Wayne Roberts |
3:c012313ebc13 | 109 | #ifdef DEBUG_SMBUS |
Wayne Roberts |
5:493e5cc9c052 | 110 | put_cbuf(CMD_ADDR_HOST_READ); // AHR |
Wayne Roberts |
3:c012313ebc13 | 111 | put_cbuf(2); |
Wayne Roberts |
3:c012313ebc13 | 112 | put_cbuf(cmd_to_length[_rx_buf[0]]); |
Wayne Roberts |
3:c012313ebc13 | 113 | put_cbuf(hdma_tx.Instance->CNDTR); |
Wayne Roberts |
3:c012313ebc13 | 114 | #endif /* DEBUG_SMBUS */ |
Wayne Roberts |
3:c012313ebc13 | 115 | SmbusHandle.Instance->CR1 |= I2C_CR1_TXDMAEN; |
Wayne Roberts |
3:c012313ebc13 | 116 | HAL_DMA_Start(&hdma_tx, (uint32_t)i2c.tx_buf, (uint32_t)&SmbusHandle.Instance->TXDR, cmd_to_length[_rx_buf[0]]); |
Wayne Roberts |
3:c012313ebc13 | 117 | |
Wayne Roberts |
3:c012313ebc13 | 118 | icr |= SMBUS_FLAG_ADDR; |
Wayne Roberts |
3:c012313ebc13 | 119 | } else if (!stopWaiting) { |
Wayne Roberts |
0:20421a857bd5 | 120 | // 0: Write transfer, slave enters receiver mode. |
Wayne Roberts |
5:493e5cc9c052 | 121 | |
Wayne Roberts |
3:c012313ebc13 | 122 | SmbusHandle.Instance->CR1 |= I2C_CR1_RXDMAEN; |
Wayne Roberts |
3:c012313ebc13 | 123 | HAL_DMA_Start(&hdma_rx, (uint32_t)&SmbusHandle.Instance->RXDR, (uint32_t)_rx_buf, sizeof(_rx_buf)); |
Wayne Roberts |
3:c012313ebc13 | 124 | |
Wayne Roberts |
3:c012313ebc13 | 125 | #ifdef DEBUG_SMBUS |
Wayne Roberts |
5:493e5cc9c052 | 126 | put_cbuf(CMD_ADDR_HOST_WRITE); // AHW |
Wayne Roberts |
3:c012313ebc13 | 127 | put_cbuf(1); |
Wayne Roberts |
5:493e5cc9c052 | 128 | put_cbuf(hdma_rx.Instance->CNDTR); |
Wayne Roberts |
3:c012313ebc13 | 129 | #endif /* DEBUG_SMBUS */ |
Wayne Roberts |
3:c012313ebc13 | 130 | |
Wayne Roberts |
3:c012313ebc13 | 131 | icr |= SMBUS_FLAG_ADDR; |
Wayne Roberts |
0:20421a857bd5 | 132 | } |
Wayne Roberts |
0:20421a857bd5 | 133 | |
Wayne Roberts |
3:c012313ebc13 | 134 | stopWaiting = true; |
Wayne Roberts |
0:20421a857bd5 | 135 | } |
Wayne Roberts |
0:20421a857bd5 | 136 | |
Wayne Roberts |
3:c012313ebc13 | 137 | #ifdef TARGET_STM32L0 |
Wayne Roberts |
3:c012313ebc13 | 138 | err_irqHandler(tmpisrvalue); |
Wayne Roberts |
3:c012313ebc13 | 139 | #endif |
Wayne Roberts |
3:c012313ebc13 | 140 | |
Wayne Roberts |
0:20421a857bd5 | 141 | if (tmpisrvalue & SMBUS_FLAG_AF) { |
Wayne Roberts |
0:20421a857bd5 | 142 | /* last byte the host wants was sent */ |
Wayne Roberts |
3:c012313ebc13 | 143 | SmbusHandle.Instance->CR1 &= ~I2C_CR1_TXDMAEN; |
Wayne Roberts |
3:c012313ebc13 | 144 | __HAL_DMA_DISABLE(&hdma_tx); |
Wayne Roberts |
3:c012313ebc13 | 145 | __HAL_UNLOCK(&hdma_tx); |
Wayne Roberts |
5:493e5cc9c052 | 146 | hdma_tx.State = HAL_DMA_STATE_READY; |
Wayne Roberts |
3:c012313ebc13 | 147 | |
Wayne Roberts |
3:c012313ebc13 | 148 | #ifdef DEBUG_SMBUS |
Wayne Roberts |
3:c012313ebc13 | 149 | put_cbuf(CMD_AF); |
Wayne Roberts |
3:c012313ebc13 | 150 | put_cbuf(1); |
Wayne Roberts |
3:c012313ebc13 | 151 | put_cbuf(hdma_tx.Instance->CNDTR); |
Wayne Roberts |
3:c012313ebc13 | 152 | #endif /* DEBUG_SMBUS */ |
Wayne Roberts |
3:c012313ebc13 | 153 | |
Wayne Roberts |
0:20421a857bd5 | 154 | icr |= SMBUS_FLAG_AF; |
Wayne Roberts |
0:20421a857bd5 | 155 | } |
Wayne Roberts |
0:20421a857bd5 | 156 | |
Wayne Roberts |
0:20421a857bd5 | 157 | if (tmpisrvalue & SMBUS_FLAG_STOPF) { |
Wayne Roberts |
3:c012313ebc13 | 158 | #ifdef DEBUG_SMBUS |
Wayne Roberts |
3:c012313ebc13 | 159 | put_cbuf(CMD_STOPF); |
Wayne Roberts |
3:c012313ebc13 | 160 | put_cbuf(0); |
Wayne Roberts |
3:c012313ebc13 | 161 | #endif /* DEBUG_SMBUS */ |
Wayne Roberts |
3:c012313ebc13 | 162 | |
Wayne Roberts |
0:20421a857bd5 | 163 | icr |= SMBUS_FLAG_STOPF; |
Wayne Roberts |
3:c012313ebc13 | 164 | if (i2cTransferDirection == 0) { |
Wayne Roberts |
3:c012313ebc13 | 165 | /* host done writing to buf */ |
Wayne Roberts |
3:c012313ebc13 | 166 | unsigned i, len; |
Wayne Roberts |
3:c012313ebc13 | 167 | |
Wayne Roberts |
3:c012313ebc13 | 168 | SmbusHandle.Instance->CR1 &= ~I2C_CR1_RXDMAEN; |
Wayne Roberts |
3:c012313ebc13 | 169 | __HAL_DMA_DISABLE(&hdma_rx); |
Wayne Roberts |
3:c012313ebc13 | 170 | __HAL_UNLOCK(&hdma_rx); |
Wayne Roberts |
5:493e5cc9c052 | 171 | hdma_rx.State = HAL_DMA_STATE_READY; |
Wayne Roberts |
3:c012313ebc13 | 172 | |
Wayne Roberts |
3:c012313ebc13 | 173 | len = sizeof(_rx_buf) - hdma_rx.Instance->CNDTR; |
Wayne Roberts |
3:c012313ebc13 | 174 | if (len > 0) { |
Wayne Roberts |
3:c012313ebc13 | 175 | /* send to mainloop */ |
Wayne Roberts |
3:c012313ebc13 | 176 | put_cbuf(_rx_buf[0]); |
Wayne Roberts |
3:c012313ebc13 | 177 | put_cbuf(len-1); |
Wayne Roberts |
3:c012313ebc13 | 178 | for (i = 1; i < len; i++) |
Wayne Roberts |
3:c012313ebc13 | 179 | put_cbuf(_rx_buf[i]); |
Wayne Roberts |
3:c012313ebc13 | 180 | } |
Wayne Roberts |
0:20421a857bd5 | 181 | } |
Wayne Roberts |
0:20421a857bd5 | 182 | |
Wayne Roberts |
0:20421a857bd5 | 183 | if (!(tmpisrvalue & SMBUS_FLAG_TXE)) { |
Wayne Roberts |
0:20421a857bd5 | 184 | /* slave wanted to send more than host wanted to receive */ |
Wayne Roberts |
0:20421a857bd5 | 185 | SmbusHandle.Instance->ISR = SMBUS_FLAG_TXE; |
Wayne Roberts |
0:20421a857bd5 | 186 | } |
Wayne Roberts |
0:20421a857bd5 | 187 | |
Wayne Roberts |
3:c012313ebc13 | 188 | stopWaiting = false; |
Wayne Roberts |
3:c012313ebc13 | 189 | } // ..if (tmpisrvalue & SMBUS_FLAG_STOPF) |
Wayne Roberts |
0:20421a857bd5 | 190 | |
Wayne Roberts |
0:20421a857bd5 | 191 | __HAL_SMBUS_CLEAR_FLAG(&SmbusHandle, icr); |
Wayne Roberts |
0:20421a857bd5 | 192 | } |
Wayne Roberts |
0:20421a857bd5 | 193 | |
Wayne Roberts |
3:c012313ebc13 | 194 | #define I2C_TIMING 0x10900CD6 |
Wayne Roberts |
3:c012313ebc13 | 195 | |
Wayne Roberts |
3:c012313ebc13 | 196 | int smbus_init( PinName sda, PinName scl, uint8_t slaveAddress) |
Wayne Roberts |
0:20421a857bd5 | 197 | { |
Wayne Roberts |
3:c012313ebc13 | 198 | DMA_Channel_TypeDef *dma_ch_tx, *dma_ch_rx; |
Wayne Roberts |
3:c012313ebc13 | 199 | uint32_t dma_req_tx, dma_req_rx; |
Wayne Roberts |
3:c012313ebc13 | 200 | RCC_PeriphCLKInitTypeDef RCC_PeriphCLKInitStruct; |
Wayne Roberts |
0:20421a857bd5 | 201 | uint32_t tmpisr; |
Wayne Roberts |
3:c012313ebc13 | 202 | I2CName i2c; |
Wayne Roberts |
3:c012313ebc13 | 203 | |
Wayne Roberts |
3:c012313ebc13 | 204 | I2CName i2c_sda = (I2CName)pinmap_peripheral(sda, PinMap_I2C_SDA); |
Wayne Roberts |
3:c012313ebc13 | 205 | I2CName i2c_scl = (I2CName)pinmap_peripheral(scl, PinMap_I2C_SCL); |
Wayne Roberts |
3:c012313ebc13 | 206 | |
Wayne Roberts |
3:c012313ebc13 | 207 | // Configure I2C pins |
Wayne Roberts |
3:c012313ebc13 | 208 | pinmap_pinout(sda, PinMap_I2C_SDA); |
Wayne Roberts |
3:c012313ebc13 | 209 | pinmap_pinout(scl, PinMap_I2C_SCL); |
Wayne Roberts |
3:c012313ebc13 | 210 | pin_mode(sda, OpenDrainNoPull); |
Wayne Roberts |
3:c012313ebc13 | 211 | pin_mode(scl, OpenDrainNoPull); |
Wayne Roberts |
3:c012313ebc13 | 212 | |
Wayne Roberts |
3:c012313ebc13 | 213 | i2c = (I2CName)pinmap_merge(i2c_sda, i2c_scl);; |
Wayne Roberts |
3:c012313ebc13 | 214 | |
Wayne Roberts |
3:c012313ebc13 | 215 | if (i2c == I2C_1) { |
Wayne Roberts |
3:c012313ebc13 | 216 | SmbusHandle.Instance = I2C1; |
Wayne Roberts |
3:c012313ebc13 | 217 | RCC_PeriphCLKInitStruct.PeriphClockSelection = RCC_PERIPHCLK_I2C1; |
Wayne Roberts |
3:c012313ebc13 | 218 | RCC_PeriphCLKInitStruct.I2c1ClockSelection = RCC_I2C1CLKSOURCE_SYSCLK; |
Wayne Roberts |
3:c012313ebc13 | 219 | __HAL_RCC_I2C1_CLK_ENABLE(); |
Wayne Roberts |
3:c012313ebc13 | 220 | event_i2cIRQ = I2C1_EV_IRQn; |
Wayne Roberts |
3:c012313ebc13 | 221 | error_i2cIRQ = I2C1_ER_IRQn; |
Wayne Roberts |
3:c012313ebc13 | 222 | |
Wayne Roberts |
3:c012313ebc13 | 223 | __HAL_RCC_DMA1_CLK_ENABLE(); |
Wayne Roberts |
3:c012313ebc13 | 224 | #ifdef TARGET_STM32L4 |
Wayne Roberts |
3:c012313ebc13 | 225 | dma_ch_tx = DMA1_Channel6; |
Wayne Roberts |
3:c012313ebc13 | 226 | dma_ch_rx = DMA1_Channel7; |
Wayne Roberts |
3:c012313ebc13 | 227 | dma_req_tx = DMA_REQUEST_3; |
Wayne Roberts |
3:c012313ebc13 | 228 | dma_req_rx = DMA_REQUEST_3; |
Wayne Roberts |
3:c012313ebc13 | 229 | #elif defined(TARGET_STM32L0) |
Wayne Roberts |
3:c012313ebc13 | 230 | dma_ch_tx = DMA1_Channel6; |
Wayne Roberts |
3:c012313ebc13 | 231 | dma_ch_rx = DMA1_Channel7; |
Wayne Roberts |
3:c012313ebc13 | 232 | dma_req_tx = DMA_REQUEST_6; |
Wayne Roberts |
3:c012313ebc13 | 233 | dma_req_rx = DMA_REQUEST_6; |
Wayne Roberts |
3:c012313ebc13 | 234 | #endif |
Wayne Roberts |
3:c012313ebc13 | 235 | } |
Wayne Roberts |
3:c012313ebc13 | 236 | #if defined I2C2_BASE |
Wayne Roberts |
3:c012313ebc13 | 237 | else if (i2c == I2C_2) { |
Wayne Roberts |
3:c012313ebc13 | 238 | SmbusHandle.Instance = I2C2; |
Wayne Roberts |
3:c012313ebc13 | 239 | RCC_PeriphCLKInitStruct.PeriphClockSelection = RCC_PERIPHCLK_I2C2; |
Wayne Roberts |
3:c012313ebc13 | 240 | #ifdef RCC_I2C2CLKSOURCE_SYSCLK |
Wayne Roberts |
3:c012313ebc13 | 241 | RCC_PeriphCLKInitStruct.I2c1ClockSelection = RCC_I2C2CLKSOURCE_SYSCLK; |
Wayne Roberts |
3:c012313ebc13 | 242 | #endif /* RCC_I2C2CLKSOURCE_SYSCLK */ |
Wayne Roberts |
3:c012313ebc13 | 243 | __HAL_RCC_I2C2_CLK_ENABLE(); |
Wayne Roberts |
3:c012313ebc13 | 244 | event_i2cIRQ = I2C2_EV_IRQn; |
Wayne Roberts |
3:c012313ebc13 | 245 | error_i2cIRQ = I2C2_ER_IRQn; |
Wayne Roberts |
0:20421a857bd5 | 246 | |
Wayne Roberts |
3:c012313ebc13 | 247 | __HAL_RCC_DMA1_CLK_ENABLE(); |
Wayne Roberts |
3:c012313ebc13 | 248 | #ifdef TARGET_STM32L4 |
Wayne Roberts |
3:c012313ebc13 | 249 | dma_ch_tx = DMA1_Channel4; |
Wayne Roberts |
3:c012313ebc13 | 250 | dma_ch_rx = DMA1_Channel5; |
Wayne Roberts |
3:c012313ebc13 | 251 | dma_req_tx = DMA_REQUEST_3; |
Wayne Roberts |
3:c012313ebc13 | 252 | dma_req_rx = DMA_REQUEST_3; |
Wayne Roberts |
3:c012313ebc13 | 253 | #elif defined(TARGET_STM32L0) |
Wayne Roberts |
3:c012313ebc13 | 254 | dma_ch_tx = DMA1_Channel4; |
Wayne Roberts |
3:c012313ebc13 | 255 | dma_ch_rx = DMA1_Channel5; |
Wayne Roberts |
3:c012313ebc13 | 256 | dma_req_tx = DMA_REQUEST_7; |
Wayne Roberts |
3:c012313ebc13 | 257 | dma_req_rx = DMA_REQUEST_7; |
Wayne Roberts |
3:c012313ebc13 | 258 | #endif |
Wayne Roberts |
3:c012313ebc13 | 259 | } |
Wayne Roberts |
3:c012313ebc13 | 260 | #endif /* I2C2_BASE */ |
Wayne Roberts |
3:c012313ebc13 | 261 | #if defined I2C3_BASE |
Wayne Roberts |
3:c012313ebc13 | 262 | else if (i2c == I2C_3) { |
Wayne Roberts |
3:c012313ebc13 | 263 | SmbusHandle.Instance = I2C3; |
Wayne Roberts |
3:c012313ebc13 | 264 | RCC_PeriphCLKInitStruct.PeriphClockSelection = RCC_PERIPHCLK_I2C3; |
Wayne Roberts |
3:c012313ebc13 | 265 | RCC_PeriphCLKInitStruct.I2c3ClockSelection = RCC_I2C3CLKSOURCE_SYSCLK; |
Wayne Roberts |
3:c012313ebc13 | 266 | __HAL_RCC_I2C3_CLK_ENABLE(); |
Wayne Roberts |
3:c012313ebc13 | 267 | event_i2cIRQ = I2C3_EV_IRQn; |
Wayne Roberts |
3:c012313ebc13 | 268 | error_i2cIRQ = I2C3_ER_IRQn; |
Wayne Roberts |
0:20421a857bd5 | 269 | |
Wayne Roberts |
3:c012313ebc13 | 270 | __HAL_RCC_DMA1_CLK_ENABLE(); |
Wayne Roberts |
3:c012313ebc13 | 271 | #ifdef TARGET_STM32L4 |
Wayne Roberts |
3:c012313ebc13 | 272 | dma_ch_tx = DMA1_Channel2; |
Wayne Roberts |
3:c012313ebc13 | 273 | dma_ch_rx = DMA1_Channel3; |
Wayne Roberts |
3:c012313ebc13 | 274 | dma_req_tx = DMA_REQUEST_3; |
Wayne Roberts |
3:c012313ebc13 | 275 | dma_req_rx = DMA_REQUEST_3; |
Wayne Roberts |
3:c012313ebc13 | 276 | #elif defined(TARGET_STM32L0) |
Wayne Roberts |
3:c012313ebc13 | 277 | dma_ch_tx = DMA1_Channel4; |
Wayne Roberts |
3:c012313ebc13 | 278 | dma_ch_rx = DMA1_Channel5; |
Wayne Roberts |
3:c012313ebc13 | 279 | dma_req_tx = DMA_REQUEST_14; |
Wayne Roberts |
3:c012313ebc13 | 280 | dma_req_rx = DMA_REQUEST_14; |
Wayne Roberts |
3:c012313ebc13 | 281 | #endif |
Wayne Roberts |
3:c012313ebc13 | 282 | } |
Wayne Roberts |
3:c012313ebc13 | 283 | #endif /* I2C3_BASE */ |
Wayne Roberts |
3:c012313ebc13 | 284 | #if defined I2C4_BASE |
Wayne Roberts |
3:c012313ebc13 | 285 | else if (i2c == I2C_4) { |
Wayne Roberts |
3:c012313ebc13 | 286 | SmbusHandle.Instance = I2C4; |
Wayne Roberts |
3:c012313ebc13 | 287 | RCC_PeriphCLKInitStruct.PeriphClockSelection = RCC_PERIPHCLK_I2C4; |
Wayne Roberts |
3:c012313ebc13 | 288 | RCC_PeriphCLKInitStruct.I2c4ClockSelection = RCC_I2C4CLKSOURCE_SYSCLK; |
Wayne Roberts |
3:c012313ebc13 | 289 | __HAL_RCC_I2C4_CLK_ENABLE(); |
Wayne Roberts |
3:c012313ebc13 | 290 | event_i2cIRQ = I2C4_EV_IRQn; |
Wayne Roberts |
3:c012313ebc13 | 291 | error_i2cIRQ = I2C4_ER_IRQn; |
Wayne Roberts |
3:c012313ebc13 | 292 | |
Wayne Roberts |
3:c012313ebc13 | 293 | #ifdef TARGET_STM32L4 |
Wayne Roberts |
3:c012313ebc13 | 294 | __HAL_RCC_DMA2_CLK_ENABLE(); |
Wayne Roberts |
3:c012313ebc13 | 295 | dma_ch_tx = DMA1_Channel1; |
Wayne Roberts |
3:c012313ebc13 | 296 | dma_ch_rx = DMA1_Channel2; |
Wayne Roberts |
3:c012313ebc13 | 297 | dma_req_tx = DMA_REQUEST_0; |
Wayne Roberts |
3:c012313ebc13 | 298 | dma_req_rx = DMA_REQUEST_0; |
Wayne Roberts |
3:c012313ebc13 | 299 | #elif defined(TARGET_STM32L0) |
Wayne Roberts |
3:c012313ebc13 | 300 | #error absent |
Wayne Roberts |
3:c012313ebc13 | 301 | #endif |
Wayne Roberts |
3:c012313ebc13 | 302 | } |
Wayne Roberts |
3:c012313ebc13 | 303 | #endif /* I2C4_BASE */ |
Wayne Roberts |
3:c012313ebc13 | 304 | else { |
Wayne Roberts |
3:c012313ebc13 | 305 | mbed_error_printf("unknown i2c %x\r\n", i2c); |
Wayne Roberts |
3:c012313ebc13 | 306 | return -1; |
Wayne Roberts |
3:c012313ebc13 | 307 | } |
Wayne Roberts |
3:c012313ebc13 | 308 | |
Wayne Roberts |
3:c012313ebc13 | 309 | HAL_RCCEx_PeriphCLKConfig(&RCC_PeriphCLKInitStruct); |
Wayne Roberts |
3:c012313ebc13 | 310 | |
Wayne Roberts |
3:c012313ebc13 | 311 | // use get_i2c_timing() from i2c_device.h? |
Wayne Roberts |
0:20421a857bd5 | 312 | SmbusHandle.Init.Timing = I2C_TIMING; |
Wayne Roberts |
0:20421a857bd5 | 313 | SmbusHandle.Init.AnalogFilter = SMBUS_ANALOGFILTER_ENABLE; |
Wayne Roberts |
0:20421a857bd5 | 314 | SmbusHandle.Init.OwnAddress1 = slaveAddress; |
Wayne Roberts |
0:20421a857bd5 | 315 | SmbusHandle.Init.AddressingMode = SMBUS_ADDRESSINGMODE_7BIT; |
Wayne Roberts |
0:20421a857bd5 | 316 | SmbusHandle.Init.DualAddressMode = SMBUS_DUALADDRESS_DISABLE; |
Wayne Roberts |
0:20421a857bd5 | 317 | SmbusHandle.Init.OwnAddress2 = 0x00; |
Wayne Roberts |
0:20421a857bd5 | 318 | SmbusHandle.Init.GeneralCallMode = SMBUS_GENERALCALL_DISABLE; |
Wayne Roberts |
0:20421a857bd5 | 319 | SmbusHandle.Init.NoStretchMode = SMBUS_NOSTRETCH_DISABLE; |
Wayne Roberts |
0:20421a857bd5 | 320 | SmbusHandle.Init.PacketErrorCheckMode = SMBUS_PEC_DISABLE; |
Wayne Roberts |
0:20421a857bd5 | 321 | SmbusHandle.Init.PeripheralMode = SMBUS_PERIPHERAL_MODE_SMBUS_SLAVE; |
Wayne Roberts |
3:c012313ebc13 | 322 | SmbusHandle.Init.SMBusTimeout = I2C_TIMEOUTR_TIMOUTEN | 0x186; |
Wayne Roberts |
0:20421a857bd5 | 323 | |
Wayne Roberts |
3:c012313ebc13 | 324 | if (HAL_SMBUS_Init(&SmbusHandle) != HAL_OK) |
Wayne Roberts |
5:493e5cc9c052 | 325 | { |
Wayne Roberts |
0:20421a857bd5 | 326 | return -1; |
Wayne Roberts |
0:20421a857bd5 | 327 | } |
Wayne Roberts |
0:20421a857bd5 | 328 | |
Wayne Roberts |
0:20421a857bd5 | 329 | tmpisr = SMBUS_IT_ADDRI | SMBUS_IT_STOPI | SMBUS_IT_NACKI | SMBUS_IT_ERRI; |
Wayne Roberts |
0:20421a857bd5 | 330 | __HAL_SMBUS_ENABLE_IT(&SmbusHandle, tmpisr); |
Wayne Roberts |
0:20421a857bd5 | 331 | |
Wayne Roberts |
3:c012313ebc13 | 332 | #ifdef TARGET_STM32L4 |
Wayne Roberts |
3:c012313ebc13 | 333 | HAL_NVIC_SetPriority(event_i2cIRQ, 0, 0); |
Wayne Roberts |
3:c012313ebc13 | 334 | HAL_NVIC_EnableIRQ(event_i2cIRQ); |
Wayne Roberts |
3:c012313ebc13 | 335 | HAL_NVIC_SetPriority(error_i2cIRQ , 0, 0); |
Wayne Roberts |
3:c012313ebc13 | 336 | HAL_NVIC_EnableIRQ(error_i2cIRQ); |
Wayne Roberts |
3:c012313ebc13 | 337 | |
Wayne Roberts |
3:c012313ebc13 | 338 | NVIC_SetVector(event_i2cIRQ, (uint32_t)SMBUSx_EV_IRQHandler); |
Wayne Roberts |
3:c012313ebc13 | 339 | NVIC_SetVector(error_i2cIRQ, (uint32_t)SMBUSx_ER_IRQHandler); |
Wayne Roberts |
5:493e5cc9c052 | 340 | |
Wayne Roberts |
3:c012313ebc13 | 341 | #else |
Wayne Roberts |
3:c012313ebc13 | 342 | HAL_NVIC_SetPriority(event_i2cIRQ, 0, 0); |
Wayne Roberts |
3:c012313ebc13 | 343 | HAL_NVIC_EnableIRQ(event_i2cIRQ); |
Wayne Roberts |
3:c012313ebc13 | 344 | |
Wayne Roberts |
3:c012313ebc13 | 345 | NVIC_SetVector(event_i2cIRQ, (uint32_t)SMBUSx_IRQHandler); |
Wayne Roberts |
3:c012313ebc13 | 346 | #endif |
Wayne Roberts |
3:c012313ebc13 | 347 | |
Wayne Roberts |
3:c012313ebc13 | 348 | /* Configure the DMA handler for Transmission process */ |
Wayne Roberts |
3:c012313ebc13 | 349 | hdma_tx.Instance = dma_ch_tx; |
Wayne Roberts |
3:c012313ebc13 | 350 | hdma_tx.Init.Request = dma_req_tx; |
Wayne Roberts |
3:c012313ebc13 | 351 | hdma_tx.Init.Direction = DMA_MEMORY_TO_PERIPH; |
Wayne Roberts |
3:c012313ebc13 | 352 | hdma_tx.Init.PeriphInc = DMA_PINC_DISABLE; |
Wayne Roberts |
3:c012313ebc13 | 353 | hdma_tx.Init.MemInc = DMA_MINC_ENABLE; |
Wayne Roberts |
3:c012313ebc13 | 354 | hdma_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE; |
Wayne Roberts |
3:c012313ebc13 | 355 | hdma_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE; |
Wayne Roberts |
3:c012313ebc13 | 356 | hdma_tx.Init.Mode = DMA_NORMAL; |
Wayne Roberts |
3:c012313ebc13 | 357 | hdma_tx.Init.Priority = DMA_PRIORITY_LOW; |
Wayne Roberts |
3:c012313ebc13 | 358 | |
Wayne Roberts |
3:c012313ebc13 | 359 | HAL_DMA_Init(&hdma_tx); |
Wayne Roberts |
3:c012313ebc13 | 360 | |
Wayne Roberts |
3:c012313ebc13 | 361 | hdma_rx.Instance = dma_ch_rx; |
Wayne Roberts |
3:c012313ebc13 | 362 | hdma_rx.Init.Request = dma_req_rx; |
Wayne Roberts |
3:c012313ebc13 | 363 | hdma_rx.Init.Direction = DMA_PERIPH_TO_MEMORY; |
Wayne Roberts |
3:c012313ebc13 | 364 | hdma_rx.Init.PeriphInc = DMA_PINC_DISABLE; |
Wayne Roberts |
3:c012313ebc13 | 365 | hdma_rx.Init.MemInc = DMA_MINC_ENABLE; |
Wayne Roberts |
3:c012313ebc13 | 366 | hdma_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE; |
Wayne Roberts |
3:c012313ebc13 | 367 | hdma_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE; |
Wayne Roberts |
3:c012313ebc13 | 368 | hdma_rx.Init.Mode = DMA_NORMAL; |
Wayne Roberts |
3:c012313ebc13 | 369 | hdma_rx.Init.Priority = DMA_PRIORITY_HIGH; |
Wayne Roberts |
3:c012313ebc13 | 370 | |
Wayne Roberts |
3:c012313ebc13 | 371 | HAL_DMA_Init(&hdma_rx); |
Wayne Roberts |
5:493e5cc9c052 | 372 | |
Wayne Roberts |
0:20421a857bd5 | 373 | return 0; |
Wayne Roberts |
0:20421a857bd5 | 374 | } |
Wayne Roberts |
0:20421a857bd5 | 375 | |
Wayne Roberts |
0:20421a857bd5 | 376 | static inline uint8_t get_cbuf() |
Wayne Roberts |
0:20421a857bd5 | 377 | { |
Wayne Roberts |
0:20421a857bd5 | 378 | uint8_t ret = i2c.cbuf[i2c.cbuf_out]; |
Wayne Roberts |
3:c012313ebc13 | 379 | if (++i2c.cbuf_out == CBUF_SIZE) |
Wayne Roberts |
0:20421a857bd5 | 380 | i2c.cbuf_out = 0; |
Wayne Roberts |
0:20421a857bd5 | 381 | |
Wayne Roberts |
0:20421a857bd5 | 382 | return ret; |
Wayne Roberts |
0:20421a857bd5 | 383 | } |
Wayne Roberts |
0:20421a857bd5 | 384 | |
Wayne Roberts |
0:20421a857bd5 | 385 | /* service_i2c(): call from main loop */ |
Wayne Roberts |
0:20421a857bd5 | 386 | void service_i2c() |
Wayne Roberts |
0:20421a857bd5 | 387 | { |
Wayne Roberts |
0:20421a857bd5 | 388 | if (i2c.cbuf_in != i2c.cbuf_out) { |
Wayne Roberts |
3:c012313ebc13 | 389 | uint8_t buf[32]; |
Wayne Roberts |
0:20421a857bd5 | 390 | uint8_t n, cmd, len; |
Wayne Roberts |
0:20421a857bd5 | 391 | cmd = get_cbuf(); |
Wayne Roberts |
0:20421a857bd5 | 392 | len = get_cbuf(); |
Wayne Roberts |
0:20421a857bd5 | 393 | /* host is writing: parse here */ |
Wayne Roberts |
0:20421a857bd5 | 394 | for (n = 0; n < len; n++) |
Wayne Roberts |
0:20421a857bd5 | 395 | buf[n] = get_cbuf(); |
Wayne Roberts |
0:20421a857bd5 | 396 | |
Wayne Roberts |
0:20421a857bd5 | 397 | /*if (len != cmd_to_length[cmd]) |
Wayne Roberts |
0:20421a857bd5 | 398 | pc.printf("[%02x != %02x] ", len, cmd_to_length[cmd]);*/ |
Wayne Roberts |
0:20421a857bd5 | 399 | |
Wayne Roberts |
0:20421a857bd5 | 400 | service_i2c_write(cmd, len, buf); |
Wayne Roberts |
0:20421a857bd5 | 401 | } |
Wayne Roberts |
0:20421a857bd5 | 402 | } |
Wayne Roberts |
0:20421a857bd5 | 403 |