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 pinmbed slaveRPi master
GND6
SCLD155
SDAD143
IRQany avail pinany 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.
/media/uploads/dudmuck/i2c_rpi_nucleo_sm_.png
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.

Committer:
Wayne Roberts
Date:
Sun Feb 03 16:52:43 2019 -0800
Revision:
3:c012313ebc13
Parent:
1:914409dc83b1
Child:
4:7ab789db70da
use dma to prevent underrun/overrun

Who changed what in which revision?

UserRevisionLine numberNew 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 3:c012313ebc13 49
Wayne Roberts 3:c012313ebc13 50 SmbusHandle.Instance->CR1 &= ~I2C_CR1_RXDMAEN;
Wayne Roberts 3:c012313ebc13 51 __HAL_DMA_DISABLE(&hdma_rx);
Wayne Roberts 3:c012313ebc13 52 __HAL_UNLOCK(&hdma_rx);
Wayne Roberts 3:c012313ebc13 53
Wayne Roberts 3:c012313ebc13 54 put_cbuf(CMD_TIMEOUT);
Wayne Roberts 3:c012313ebc13 55 put_cbuf(1);
Wayne Roberts 3:c012313ebc13 56 put_cbuf(hdma_tx.Instance->CNDTR); // req[0]
Wayne Roberts 3:c012313ebc13 57
Wayne Roberts 3:c012313ebc13 58 _icr |= SMBUS_FLAG_TIMEOUT;
Wayne Roberts 3:c012313ebc13 59 }
Wayne Roberts 3:c012313ebc13 60
Wayne Roberts 3:c012313ebc13 61 __HAL_SMBUS_CLEAR_FLAG(&SmbusHandle, _icr);
Wayne Roberts 3:c012313ebc13 62 }
Wayne Roberts 0:20421a857bd5 63
Wayne Roberts 0:20421a857bd5 64 #ifdef TARGET_STM32L4
Wayne Roberts 0:20421a857bd5 65 void SMBUSx_ER_IRQHandler()
Wayne Roberts 0:20421a857bd5 66 {
Wayne Roberts 3:c012313ebc13 67 err_irqHandler(SMBUS_GET_ISR_REG(&SmbusHandle));
Wayne Roberts 0:20421a857bd5 68 }
Wayne Roberts 0:20421a857bd5 69
Wayne Roberts 0:20421a857bd5 70 void SMBUSx_EV_IRQHandler(void)
Wayne Roberts 0:20421a857bd5 71 #else
Wayne Roberts 0:20421a857bd5 72 void SMBUSx_IRQHandler(void)
Wayne Roberts 0:20421a857bd5 73 #endif
Wayne Roberts 0:20421a857bd5 74 {
Wayne Roberts 0:20421a857bd5 75 uint32_t tmpisrvalue = SMBUS_GET_ISR_REG(&SmbusHandle);
Wayne Roberts 0:20421a857bd5 76 uint32_t icr = 0;
Wayne Roberts 3:c012313ebc13 77
Wayne Roberts 0:20421a857bd5 78 static bool i2cTransferDirection; // true = read
Wayne Roberts 3:c012313ebc13 79 static bool stopWaiting = false;
Wayne Roberts 3:c012313ebc13 80
Wayne Roberts 3:c012313ebc13 81 static uint8_t _rx_buf[33]; // [0] is cmd
Wayne Roberts 0:20421a857bd5 82
Wayne Roberts 3:c012313ebc13 83 /* often multiple flags are set simultaneously, yet must still be taken in correct order */
Wayne Roberts 0:20421a857bd5 84
Wayne Roberts 3:c012313ebc13 85 #ifdef DEBUG_SMBUS
Wayne Roberts 3:c012313ebc13 86 put_cbuf(CMD_ISR);
Wayne Roberts 3:c012313ebc13 87 put_cbuf(1);
Wayne Roberts 3:c012313ebc13 88 put_cbuf(tmpisrvalue & 0xff);
Wayne Roberts 3:c012313ebc13 89 #endif /* DEBUG_SMBUS */
Wayne Roberts 0:20421a857bd5 90
Wayne Roberts 0:20421a857bd5 91 if (tmpisrvalue & SMBUS_FLAG_ADDR) {
Wayne Roberts 0:20421a857bd5 92 i2cTransferDirection = SMBUS_GET_DIR(&SmbusHandle);
Wayne Roberts 3:c012313ebc13 93 if (i2cTransferDirection) { // if host read
Wayne Roberts 0:20421a857bd5 94 // 1: Read transfer, slave enters transmitter mode.. cmd has already been provided
Wayne Roberts 3:c012313ebc13 95 SmbusHandle.Instance->CR1 &= ~I2C_CR1_RXDMAEN;
Wayne Roberts 3:c012313ebc13 96 __HAL_DMA_DISABLE(&hdma_rx);
Wayne Roberts 3:c012313ebc13 97 __HAL_UNLOCK(&hdma_rx);
Wayne Roberts 3:c012313ebc13 98
Wayne Roberts 3:c012313ebc13 99 fill_tx_buf(_rx_buf[0]);
Wayne Roberts 0:20421a857bd5 100
Wayne Roberts 3:c012313ebc13 101 #ifdef DEBUG_SMBUS
Wayne Roberts 3:c012313ebc13 102 put_cbuf(CMD_ADDR_HOST_READ);
Wayne Roberts 3:c012313ebc13 103 put_cbuf(2);
Wayne Roberts 3:c012313ebc13 104 put_cbuf(cmd_to_length[_rx_buf[0]]);
Wayne Roberts 3:c012313ebc13 105 put_cbuf(hdma_tx.Instance->CNDTR);
Wayne Roberts 3:c012313ebc13 106 #endif /* DEBUG_SMBUS */
Wayne Roberts 3:c012313ebc13 107 SmbusHandle.Instance->CR1 |= I2C_CR1_TXDMAEN;
Wayne Roberts 3:c012313ebc13 108 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 109
Wayne Roberts 3:c012313ebc13 110 icr |= SMBUS_FLAG_ADDR;
Wayne Roberts 3:c012313ebc13 111 } else if (!stopWaiting) {
Wayne Roberts 0:20421a857bd5 112 // 0: Write transfer, slave enters receiver mode.
Wayne Roberts 3:c012313ebc13 113 SmbusHandle.Instance->CR1 |= I2C_CR1_RXDMAEN;
Wayne Roberts 3:c012313ebc13 114 HAL_DMA_Start(&hdma_rx, (uint32_t)&SmbusHandle.Instance->RXDR, (uint32_t)_rx_buf, sizeof(_rx_buf));
Wayne Roberts 3:c012313ebc13 115
Wayne Roberts 3:c012313ebc13 116 #ifdef DEBUG_SMBUS
Wayne Roberts 3:c012313ebc13 117 put_cbuf(CMD_ADDR_HOST_WRITE);
Wayne Roberts 3:c012313ebc13 118 put_cbuf(1);
Wayne Roberts 3:c012313ebc13 119 put_cbuf(sizeof(_rx_buf));
Wayne Roberts 3:c012313ebc13 120 #endif /* DEBUG_SMBUS */
Wayne Roberts 3:c012313ebc13 121
Wayne Roberts 3:c012313ebc13 122 icr |= SMBUS_FLAG_ADDR;
Wayne Roberts 0:20421a857bd5 123 }
Wayne Roberts 0:20421a857bd5 124
Wayne Roberts 3:c012313ebc13 125 stopWaiting = true;
Wayne Roberts 0:20421a857bd5 126 }
Wayne Roberts 0:20421a857bd5 127
Wayne Roberts 3:c012313ebc13 128 #ifdef TARGET_STM32L0
Wayne Roberts 3:c012313ebc13 129 err_irqHandler(tmpisrvalue);
Wayne Roberts 3:c012313ebc13 130 #endif
Wayne Roberts 3:c012313ebc13 131
Wayne Roberts 0:20421a857bd5 132 if (tmpisrvalue & SMBUS_FLAG_AF) {
Wayne Roberts 0:20421a857bd5 133 /* last byte the host wants was sent */
Wayne Roberts 3:c012313ebc13 134 SmbusHandle.Instance->CR1 &= ~I2C_CR1_TXDMAEN;
Wayne Roberts 3:c012313ebc13 135 __HAL_DMA_DISABLE(&hdma_tx);
Wayne Roberts 3:c012313ebc13 136 __HAL_UNLOCK(&hdma_tx);
Wayne Roberts 3:c012313ebc13 137
Wayne Roberts 3:c012313ebc13 138 #ifdef DEBUG_SMBUS
Wayne Roberts 3:c012313ebc13 139 put_cbuf(CMD_AF);
Wayne Roberts 3:c012313ebc13 140 put_cbuf(1);
Wayne Roberts 3:c012313ebc13 141 put_cbuf(hdma_tx.Instance->CNDTR);
Wayne Roberts 3:c012313ebc13 142 #endif /* DEBUG_SMBUS */
Wayne Roberts 3:c012313ebc13 143
Wayne Roberts 0:20421a857bd5 144 icr |= SMBUS_FLAG_AF;
Wayne Roberts 0:20421a857bd5 145 }
Wayne Roberts 0:20421a857bd5 146
Wayne Roberts 0:20421a857bd5 147 if (tmpisrvalue & SMBUS_FLAG_STOPF) {
Wayne Roberts 3:c012313ebc13 148 #ifdef DEBUG_SMBUS
Wayne Roberts 3:c012313ebc13 149 put_cbuf(CMD_STOPF);
Wayne Roberts 3:c012313ebc13 150 put_cbuf(0);
Wayne Roberts 3:c012313ebc13 151 #endif /* DEBUG_SMBUS */
Wayne Roberts 3:c012313ebc13 152
Wayne Roberts 0:20421a857bd5 153 icr |= SMBUS_FLAG_STOPF;
Wayne Roberts 3:c012313ebc13 154 if (i2cTransferDirection == 0) {
Wayne Roberts 3:c012313ebc13 155 /* host done writing to buf */
Wayne Roberts 3:c012313ebc13 156 unsigned i, len;
Wayne Roberts 3:c012313ebc13 157
Wayne Roberts 3:c012313ebc13 158 SmbusHandle.Instance->CR1 &= ~I2C_CR1_RXDMAEN;
Wayne Roberts 3:c012313ebc13 159 __HAL_DMA_DISABLE(&hdma_rx);
Wayne Roberts 3:c012313ebc13 160 __HAL_UNLOCK(&hdma_rx);
Wayne Roberts 3:c012313ebc13 161
Wayne Roberts 3:c012313ebc13 162 len = sizeof(_rx_buf) - hdma_rx.Instance->CNDTR;
Wayne Roberts 3:c012313ebc13 163 if (len > 0) {
Wayne Roberts 3:c012313ebc13 164 /* send to mainloop */
Wayne Roberts 3:c012313ebc13 165 put_cbuf(_rx_buf[0]);
Wayne Roberts 3:c012313ebc13 166 put_cbuf(len-1);
Wayne Roberts 3:c012313ebc13 167 for (i = 1; i < len; i++)
Wayne Roberts 3:c012313ebc13 168 put_cbuf(_rx_buf[i]);
Wayne Roberts 3:c012313ebc13 169 }
Wayne Roberts 0:20421a857bd5 170 }
Wayne Roberts 0:20421a857bd5 171
Wayne Roberts 0:20421a857bd5 172 if (!(tmpisrvalue & SMBUS_FLAG_TXE)) {
Wayne Roberts 0:20421a857bd5 173 /* slave wanted to send more than host wanted to receive */
Wayne Roberts 0:20421a857bd5 174 SmbusHandle.Instance->ISR = SMBUS_FLAG_TXE;
Wayne Roberts 0:20421a857bd5 175 }
Wayne Roberts 0:20421a857bd5 176
Wayne Roberts 3:c012313ebc13 177 stopWaiting = false;
Wayne Roberts 3:c012313ebc13 178 } // ..if (tmpisrvalue & SMBUS_FLAG_STOPF)
Wayne Roberts 0:20421a857bd5 179
Wayne Roberts 0:20421a857bd5 180 __HAL_SMBUS_CLEAR_FLAG(&SmbusHandle, icr);
Wayne Roberts 0:20421a857bd5 181 }
Wayne Roberts 0:20421a857bd5 182
Wayne Roberts 3:c012313ebc13 183 #define I2C_TIMING 0x10900CD6
Wayne Roberts 3:c012313ebc13 184
Wayne Roberts 3:c012313ebc13 185 int smbus_init( PinName sda, PinName scl, uint8_t slaveAddress)
Wayne Roberts 0:20421a857bd5 186 {
Wayne Roberts 3:c012313ebc13 187 DMA_Channel_TypeDef *dma_ch_tx, *dma_ch_rx;
Wayne Roberts 3:c012313ebc13 188 uint32_t dma_req_tx, dma_req_rx;
Wayne Roberts 3:c012313ebc13 189 RCC_PeriphCLKInitTypeDef RCC_PeriphCLKInitStruct;
Wayne Roberts 0:20421a857bd5 190 uint32_t tmpisr;
Wayne Roberts 3:c012313ebc13 191 I2CName i2c;
Wayne Roberts 3:c012313ebc13 192
Wayne Roberts 3:c012313ebc13 193 I2CName i2c_sda = (I2CName)pinmap_peripheral(sda, PinMap_I2C_SDA);
Wayne Roberts 3:c012313ebc13 194 I2CName i2c_scl = (I2CName)pinmap_peripheral(scl, PinMap_I2C_SCL);
Wayne Roberts 3:c012313ebc13 195
Wayne Roberts 3:c012313ebc13 196 // Configure I2C pins
Wayne Roberts 3:c012313ebc13 197 pinmap_pinout(sda, PinMap_I2C_SDA);
Wayne Roberts 3:c012313ebc13 198 pinmap_pinout(scl, PinMap_I2C_SCL);
Wayne Roberts 3:c012313ebc13 199 pin_mode(sda, OpenDrainNoPull);
Wayne Roberts 3:c012313ebc13 200 pin_mode(scl, OpenDrainNoPull);
Wayne Roberts 3:c012313ebc13 201
Wayne Roberts 3:c012313ebc13 202 i2c = (I2CName)pinmap_merge(i2c_sda, i2c_scl);;
Wayne Roberts 3:c012313ebc13 203
Wayne Roberts 3:c012313ebc13 204 if (i2c == I2C_1) {
Wayne Roberts 3:c012313ebc13 205 SmbusHandle.Instance = I2C1;
Wayne Roberts 3:c012313ebc13 206 RCC_PeriphCLKInitStruct.PeriphClockSelection = RCC_PERIPHCLK_I2C1;
Wayne Roberts 3:c012313ebc13 207 RCC_PeriphCLKInitStruct.I2c1ClockSelection = RCC_I2C1CLKSOURCE_SYSCLK;
Wayne Roberts 3:c012313ebc13 208 __HAL_RCC_I2C1_CLK_ENABLE();
Wayne Roberts 3:c012313ebc13 209 event_i2cIRQ = I2C1_EV_IRQn;
Wayne Roberts 3:c012313ebc13 210 error_i2cIRQ = I2C1_ER_IRQn;
Wayne Roberts 3:c012313ebc13 211
Wayne Roberts 3:c012313ebc13 212 __HAL_RCC_DMA1_CLK_ENABLE();
Wayne Roberts 3:c012313ebc13 213 #ifdef TARGET_STM32L4
Wayne Roberts 3:c012313ebc13 214 dma_ch_tx = DMA1_Channel6;
Wayne Roberts 3:c012313ebc13 215 dma_ch_rx = DMA1_Channel7;
Wayne Roberts 3:c012313ebc13 216 dma_req_tx = DMA_REQUEST_3;
Wayne Roberts 3:c012313ebc13 217 dma_req_rx = DMA_REQUEST_3;
Wayne Roberts 3:c012313ebc13 218 #elif defined(TARGET_STM32L0)
Wayne Roberts 3:c012313ebc13 219 dma_ch_tx = DMA1_Channel6;
Wayne Roberts 3:c012313ebc13 220 dma_ch_rx = DMA1_Channel7;
Wayne Roberts 3:c012313ebc13 221 dma_req_tx = DMA_REQUEST_6;
Wayne Roberts 3:c012313ebc13 222 dma_req_rx = DMA_REQUEST_6;
Wayne Roberts 3:c012313ebc13 223 #endif
Wayne Roberts 3:c012313ebc13 224 }
Wayne Roberts 3:c012313ebc13 225 #if defined I2C2_BASE
Wayne Roberts 3:c012313ebc13 226 else if (i2c == I2C_2) {
Wayne Roberts 3:c012313ebc13 227 SmbusHandle.Instance = I2C2;
Wayne Roberts 3:c012313ebc13 228 RCC_PeriphCLKInitStruct.PeriphClockSelection = RCC_PERIPHCLK_I2C2;
Wayne Roberts 3:c012313ebc13 229 #ifdef RCC_I2C2CLKSOURCE_SYSCLK
Wayne Roberts 3:c012313ebc13 230 RCC_PeriphCLKInitStruct.I2c1ClockSelection = RCC_I2C2CLKSOURCE_SYSCLK;
Wayne Roberts 3:c012313ebc13 231 #endif /* RCC_I2C2CLKSOURCE_SYSCLK */
Wayne Roberts 3:c012313ebc13 232 __HAL_RCC_I2C2_CLK_ENABLE();
Wayne Roberts 3:c012313ebc13 233 event_i2cIRQ = I2C2_EV_IRQn;
Wayne Roberts 3:c012313ebc13 234 error_i2cIRQ = I2C2_ER_IRQn;
Wayne Roberts 0:20421a857bd5 235
Wayne Roberts 3:c012313ebc13 236 __HAL_RCC_DMA1_CLK_ENABLE();
Wayne Roberts 3:c012313ebc13 237 #ifdef TARGET_STM32L4
Wayne Roberts 3:c012313ebc13 238 dma_ch_tx = DMA1_Channel4;
Wayne Roberts 3:c012313ebc13 239 dma_ch_rx = DMA1_Channel5;
Wayne Roberts 3:c012313ebc13 240 dma_req_tx = DMA_REQUEST_3;
Wayne Roberts 3:c012313ebc13 241 dma_req_rx = DMA_REQUEST_3;
Wayne Roberts 3:c012313ebc13 242 #elif defined(TARGET_STM32L0)
Wayne Roberts 3:c012313ebc13 243 dma_ch_tx = DMA1_Channel4;
Wayne Roberts 3:c012313ebc13 244 dma_ch_rx = DMA1_Channel5;
Wayne Roberts 3:c012313ebc13 245 dma_req_tx = DMA_REQUEST_7;
Wayne Roberts 3:c012313ebc13 246 dma_req_rx = DMA_REQUEST_7;
Wayne Roberts 3:c012313ebc13 247 #endif
Wayne Roberts 3:c012313ebc13 248 }
Wayne Roberts 3:c012313ebc13 249 #endif /* I2C2_BASE */
Wayne Roberts 3:c012313ebc13 250 #if defined I2C3_BASE
Wayne Roberts 3:c012313ebc13 251 else if (i2c == I2C_3) {
Wayne Roberts 3:c012313ebc13 252 SmbusHandle.Instance = I2C3;
Wayne Roberts 3:c012313ebc13 253 RCC_PeriphCLKInitStruct.PeriphClockSelection = RCC_PERIPHCLK_I2C3;
Wayne Roberts 3:c012313ebc13 254 RCC_PeriphCLKInitStruct.I2c3ClockSelection = RCC_I2C3CLKSOURCE_SYSCLK;
Wayne Roberts 3:c012313ebc13 255 __HAL_RCC_I2C3_CLK_ENABLE();
Wayne Roberts 3:c012313ebc13 256 event_i2cIRQ = I2C3_EV_IRQn;
Wayne Roberts 3:c012313ebc13 257 error_i2cIRQ = I2C3_ER_IRQn;
Wayne Roberts 0:20421a857bd5 258
Wayne Roberts 3:c012313ebc13 259 __HAL_RCC_DMA1_CLK_ENABLE();
Wayne Roberts 3:c012313ebc13 260 #ifdef TARGET_STM32L4
Wayne Roberts 3:c012313ebc13 261 dma_ch_tx = DMA1_Channel2;
Wayne Roberts 3:c012313ebc13 262 dma_ch_rx = DMA1_Channel3;
Wayne Roberts 3:c012313ebc13 263 dma_req_tx = DMA_REQUEST_3;
Wayne Roberts 3:c012313ebc13 264 dma_req_rx = DMA_REQUEST_3;
Wayne Roberts 3:c012313ebc13 265 #elif defined(TARGET_STM32L0)
Wayne Roberts 3:c012313ebc13 266 dma_ch_tx = DMA1_Channel4;
Wayne Roberts 3:c012313ebc13 267 dma_ch_rx = DMA1_Channel5;
Wayne Roberts 3:c012313ebc13 268 dma_req_tx = DMA_REQUEST_14;
Wayne Roberts 3:c012313ebc13 269 dma_req_rx = DMA_REQUEST_14;
Wayne Roberts 3:c012313ebc13 270 #endif
Wayne Roberts 3:c012313ebc13 271 }
Wayne Roberts 3:c012313ebc13 272 #endif /* I2C3_BASE */
Wayne Roberts 3:c012313ebc13 273 #if defined I2C4_BASE
Wayne Roberts 3:c012313ebc13 274 else if (i2c == I2C_4) {
Wayne Roberts 3:c012313ebc13 275 SmbusHandle.Instance = I2C4;
Wayne Roberts 3:c012313ebc13 276 RCC_PeriphCLKInitStruct.PeriphClockSelection = RCC_PERIPHCLK_I2C4;
Wayne Roberts 3:c012313ebc13 277 RCC_PeriphCLKInitStruct.I2c4ClockSelection = RCC_I2C4CLKSOURCE_SYSCLK;
Wayne Roberts 3:c012313ebc13 278 __HAL_RCC_I2C4_CLK_ENABLE();
Wayne Roberts 3:c012313ebc13 279 event_i2cIRQ = I2C4_EV_IRQn;
Wayne Roberts 3:c012313ebc13 280 error_i2cIRQ = I2C4_ER_IRQn;
Wayne Roberts 3:c012313ebc13 281
Wayne Roberts 3:c012313ebc13 282 #ifdef TARGET_STM32L4
Wayne Roberts 3:c012313ebc13 283 __HAL_RCC_DMA2_CLK_ENABLE();
Wayne Roberts 3:c012313ebc13 284 dma_ch_tx = DMA1_Channel1;
Wayne Roberts 3:c012313ebc13 285 dma_ch_rx = DMA1_Channel2;
Wayne Roberts 3:c012313ebc13 286 dma_req_tx = DMA_REQUEST_0;
Wayne Roberts 3:c012313ebc13 287 dma_req_rx = DMA_REQUEST_0;
Wayne Roberts 3:c012313ebc13 288 #elif defined(TARGET_STM32L0)
Wayne Roberts 3:c012313ebc13 289 #error absent
Wayne Roberts 3:c012313ebc13 290 #endif
Wayne Roberts 3:c012313ebc13 291 }
Wayne Roberts 3:c012313ebc13 292 #endif /* I2C4_BASE */
Wayne Roberts 3:c012313ebc13 293 else {
Wayne Roberts 3:c012313ebc13 294 mbed_error_printf("unknown i2c %x\r\n", i2c);
Wayne Roberts 3:c012313ebc13 295 return -1;
Wayne Roberts 3:c012313ebc13 296 }
Wayne Roberts 3:c012313ebc13 297
Wayne Roberts 3:c012313ebc13 298 HAL_RCCEx_PeriphCLKConfig(&RCC_PeriphCLKInitStruct);
Wayne Roberts 3:c012313ebc13 299
Wayne Roberts 3:c012313ebc13 300 // use get_i2c_timing() from i2c_device.h?
Wayne Roberts 0:20421a857bd5 301 SmbusHandle.Init.Timing = I2C_TIMING;
Wayne Roberts 0:20421a857bd5 302 SmbusHandle.Init.AnalogFilter = SMBUS_ANALOGFILTER_ENABLE;
Wayne Roberts 0:20421a857bd5 303 SmbusHandle.Init.OwnAddress1 = slaveAddress;
Wayne Roberts 0:20421a857bd5 304 SmbusHandle.Init.AddressingMode = SMBUS_ADDRESSINGMODE_7BIT;
Wayne Roberts 0:20421a857bd5 305 SmbusHandle.Init.DualAddressMode = SMBUS_DUALADDRESS_DISABLE;
Wayne Roberts 0:20421a857bd5 306 SmbusHandle.Init.OwnAddress2 = 0x00;
Wayne Roberts 0:20421a857bd5 307 SmbusHandle.Init.GeneralCallMode = SMBUS_GENERALCALL_DISABLE;
Wayne Roberts 0:20421a857bd5 308 SmbusHandle.Init.NoStretchMode = SMBUS_NOSTRETCH_DISABLE;
Wayne Roberts 0:20421a857bd5 309 SmbusHandle.Init.PacketErrorCheckMode = SMBUS_PEC_DISABLE;
Wayne Roberts 0:20421a857bd5 310 SmbusHandle.Init.PeripheralMode = SMBUS_PERIPHERAL_MODE_SMBUS_SLAVE;
Wayne Roberts 3:c012313ebc13 311 SmbusHandle.Init.SMBusTimeout = I2C_TIMEOUTR_TIMOUTEN | 0x186;
Wayne Roberts 0:20421a857bd5 312
Wayne Roberts 3:c012313ebc13 313 if (HAL_SMBUS_Init(&SmbusHandle) != HAL_OK)
Wayne Roberts 0:20421a857bd5 314 {
Wayne Roberts 0:20421a857bd5 315 return -1;
Wayne Roberts 0:20421a857bd5 316 }
Wayne Roberts 0:20421a857bd5 317
Wayne Roberts 0:20421a857bd5 318 tmpisr = SMBUS_IT_ADDRI | SMBUS_IT_STOPI | SMBUS_IT_NACKI | SMBUS_IT_ERRI;
Wayne Roberts 0:20421a857bd5 319 __HAL_SMBUS_ENABLE_IT(&SmbusHandle, tmpisr);
Wayne Roberts 0:20421a857bd5 320
Wayne Roberts 3:c012313ebc13 321 #ifdef TARGET_STM32L4
Wayne Roberts 3:c012313ebc13 322 HAL_NVIC_SetPriority(event_i2cIRQ, 0, 0);
Wayne Roberts 3:c012313ebc13 323 HAL_NVIC_EnableIRQ(event_i2cIRQ);
Wayne Roberts 3:c012313ebc13 324 HAL_NVIC_SetPriority(error_i2cIRQ , 0, 0);
Wayne Roberts 3:c012313ebc13 325 HAL_NVIC_EnableIRQ(error_i2cIRQ);
Wayne Roberts 3:c012313ebc13 326
Wayne Roberts 3:c012313ebc13 327 NVIC_SetVector(event_i2cIRQ, (uint32_t)SMBUSx_EV_IRQHandler);
Wayne Roberts 3:c012313ebc13 328 NVIC_SetVector(error_i2cIRQ, (uint32_t)SMBUSx_ER_IRQHandler);
Wayne Roberts 3:c012313ebc13 329
Wayne Roberts 3:c012313ebc13 330 #else
Wayne Roberts 3:c012313ebc13 331 HAL_NVIC_SetPriority(event_i2cIRQ, 0, 0);
Wayne Roberts 3:c012313ebc13 332 HAL_NVIC_EnableIRQ(event_i2cIRQ);
Wayne Roberts 3:c012313ebc13 333
Wayne Roberts 3:c012313ebc13 334 NVIC_SetVector(event_i2cIRQ, (uint32_t)SMBUSx_IRQHandler);
Wayne Roberts 3:c012313ebc13 335 #endif
Wayne Roberts 3:c012313ebc13 336
Wayne Roberts 3:c012313ebc13 337 /* Configure the DMA handler for Transmission process */
Wayne Roberts 3:c012313ebc13 338 hdma_tx.Instance = dma_ch_tx;
Wayne Roberts 3:c012313ebc13 339 hdma_tx.Init.Request = dma_req_tx;
Wayne Roberts 3:c012313ebc13 340 hdma_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
Wayne Roberts 3:c012313ebc13 341 hdma_tx.Init.PeriphInc = DMA_PINC_DISABLE;
Wayne Roberts 3:c012313ebc13 342 hdma_tx.Init.MemInc = DMA_MINC_ENABLE;
Wayne Roberts 3:c012313ebc13 343 hdma_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
Wayne Roberts 3:c012313ebc13 344 hdma_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
Wayne Roberts 3:c012313ebc13 345 hdma_tx.Init.Mode = DMA_NORMAL;
Wayne Roberts 3:c012313ebc13 346 hdma_tx.Init.Priority = DMA_PRIORITY_LOW;
Wayne Roberts 3:c012313ebc13 347
Wayne Roberts 3:c012313ebc13 348 HAL_DMA_Init(&hdma_tx);
Wayne Roberts 3:c012313ebc13 349
Wayne Roberts 3:c012313ebc13 350 hdma_rx.Instance = dma_ch_rx;
Wayne Roberts 3:c012313ebc13 351 hdma_rx.Init.Request = dma_req_rx;
Wayne Roberts 3:c012313ebc13 352 hdma_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
Wayne Roberts 3:c012313ebc13 353 hdma_rx.Init.PeriphInc = DMA_PINC_DISABLE;
Wayne Roberts 3:c012313ebc13 354 hdma_rx.Init.MemInc = DMA_MINC_ENABLE;
Wayne Roberts 3:c012313ebc13 355 hdma_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
Wayne Roberts 3:c012313ebc13 356 hdma_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
Wayne Roberts 3:c012313ebc13 357 hdma_rx.Init.Mode = DMA_NORMAL;
Wayne Roberts 3:c012313ebc13 358 hdma_rx.Init.Priority = DMA_PRIORITY_HIGH;
Wayne Roberts 3:c012313ebc13 359
Wayne Roberts 3:c012313ebc13 360 HAL_DMA_Init(&hdma_rx);
Wayne Roberts 3:c012313ebc13 361
Wayne Roberts 0:20421a857bd5 362 return 0;
Wayne Roberts 0:20421a857bd5 363 }
Wayne Roberts 0:20421a857bd5 364
Wayne Roberts 0:20421a857bd5 365 static inline uint8_t get_cbuf()
Wayne Roberts 0:20421a857bd5 366 {
Wayne Roberts 0:20421a857bd5 367 uint8_t ret = i2c.cbuf[i2c.cbuf_out];
Wayne Roberts 3:c012313ebc13 368 if (++i2c.cbuf_out == CBUF_SIZE)
Wayne Roberts 0:20421a857bd5 369 i2c.cbuf_out = 0;
Wayne Roberts 0:20421a857bd5 370
Wayne Roberts 0:20421a857bd5 371 return ret;
Wayne Roberts 0:20421a857bd5 372 }
Wayne Roberts 0:20421a857bd5 373
Wayne Roberts 0:20421a857bd5 374 /* service_i2c(): call from main loop */
Wayne Roberts 0:20421a857bd5 375 void service_i2c()
Wayne Roberts 0:20421a857bd5 376 {
Wayne Roberts 0:20421a857bd5 377 if (i2c.cbuf_in != i2c.cbuf_out) {
Wayne Roberts 3:c012313ebc13 378 uint8_t buf[32];
Wayne Roberts 0:20421a857bd5 379 uint8_t n, cmd, len;
Wayne Roberts 0:20421a857bd5 380 cmd = get_cbuf();
Wayne Roberts 0:20421a857bd5 381 len = get_cbuf();
Wayne Roberts 0:20421a857bd5 382 /* host is writing: parse here */
Wayne Roberts 0:20421a857bd5 383 for (n = 0; n < len; n++)
Wayne Roberts 0:20421a857bd5 384 buf[n] = get_cbuf();
Wayne Roberts 0:20421a857bd5 385
Wayne Roberts 0:20421a857bd5 386 /*if (len != cmd_to_length[cmd])
Wayne Roberts 0:20421a857bd5 387 pc.printf("[%02x != %02x] ", len, cmd_to_length[cmd]);*/
Wayne Roberts 0:20421a857bd5 388
Wayne Roberts 0:20421a857bd5 389 service_i2c_write(cmd, len, buf);
Wayne Roberts 0:20421a857bd5 390 }
Wayne Roberts 0:20421a857bd5 391 }
Wayne Roberts 0:20421a857bd5 392