APM:Libraries
spi.c
Go to the documentation of this file.
1 /*
2 
3 (c) 2017 night_ghost@ykoctpa.ru
4 
5 based on: datasheet and logical analyser
6 
7 */
8 
9 
10 #pragma GCC optimize ("O2")
11 
12 #include <spi.h>
13 #include <hal.h>
14 
15 /*
16  * SPI devices
17  */
18 
19 static spi_state spi1_state IN_CCM;
20 static spi_state spi2_state IN_CCM;
21 static spi_state spi3_state IN_CCM;
22 
23 static const spi_dev spi1 = {
24  .SPIx = SPI1,
25  .afio = GPIO_AF_SPI1,
26  .irq = SPI1_IRQn,
27  .clock = RCC_APB2Periph_SPI1,
28  .dma = { DMA_CR_CH3, DMA2_STREAM2, DMA2_STREAM3 }, // SPI1, see Errata: DMA2 transfers can spoils data
29  .state = &spi1_state,
30 };
32 const spi_dev * const _SPI1 = &spi1;
33 
34 static const spi_dev spi2 = {
35  .SPIx = SPI2,
36  .afio = GPIO_AF_SPI2,
37  .irq = SPI2_IRQn,
38  .clock = RCC_APB1Periph_SPI2,
39  .dma = { DMA_CR_CH0, DMA1_STREAM3, DMA1_STREAM4 }, // SPI2
40  .state = &spi2_state,
41 };
43 const spi_dev * const _SPI2 = &spi2;
44 
45 static const spi_dev spi3 = {
46  .SPIx = SPI3,
47  .afio = GPIO_AF_SPI3,
48  .irq = SPI3_IRQn,
49  .clock = RCC_APB1Periph_SPI3,
50  .dma = { DMA_CR_CH0, DMA1_STREAM2, DMA1_STREAM5 }, // SPI3
51  .state = &spi3_state,
52 };
54 const spi_dev * const _SPI3 = &spi3;
55 
56 
57 void spi_init(const spi_dev *dev) {
58 
59  if (dev->SPIx == SPI1) {
60  RCC_APB2PeriphResetCmd(RCC_APB2Periph_SPI1, ENABLE);
61  RCC_APB2PeriphResetCmd(RCC_APB2Periph_SPI1, DISABLE);
62  } else if (dev->SPIx == SPI2) {
63  RCC_APB1PeriphResetCmd(RCC_APB1Periph_SPI2, ENABLE);
64  RCC_APB1PeriphResetCmd(RCC_APB1Periph_SPI2, DISABLE);
65  } else if (dev->SPIx == SPI3) {
66  RCC_APB1PeriphResetCmd(RCC_APB1Periph_SPI3, ENABLE);
67  RCC_APB1PeriphResetCmd(RCC_APB1Periph_SPI3, DISABLE);
68  } else if (dev->SPIx == SPI4) {
69  RCC_APB2PeriphResetCmd(RCC_APB2Periph_SPI4, ENABLE);
70  RCC_APB2PeriphResetCmd(RCC_APB2Periph_SPI4, DISABLE);
71  } else if (dev->SPIx == SPI5) {
72  RCC_APB2PeriphResetCmd(RCC_APB2Periph_SPI5, ENABLE);
73  RCC_APB2PeriphResetCmd(RCC_APB2Periph_SPI5, DISABLE);
74  } else if (dev->SPIx == SPI6) {
75  RCC_APB2PeriphResetCmd(RCC_APB2Periph_SPI6, ENABLE);
76  RCC_APB2PeriphResetCmd(RCC_APB2Periph_SPI6, DISABLE);
77  }
78 }
79 
84 void spi_foreach(void (*fn)(const spi_dev*)) {
85  fn(_SPI1);
86  fn(_SPI2);
87  fn(_SPI3);
88 }
89 
90 
91 
93  const gpio_dev *comm_dev,
94  uint8_t sck_bit,
95  uint8_t miso_bit,
96  uint8_t mosi_bit) {
97 
98 
99  /* Configure SCK pin */
100  gpio_set_mode(comm_dev, sck_bit, GPIO_AF_OUTPUT_PP);
101  gpio_set_af_mode(comm_dev, sck_bit, dev->afio);
102  gpio_set_speed(comm_dev, sck_bit, GPIO_speed_100MHz);
103 
104  /* Configure MISO pin */
105  gpio_set_mode(comm_dev, miso_bit, GPIO_AF_OUTPUT_OD_PU);
106  gpio_set_af_mode(comm_dev, miso_bit, dev->afio);
107  gpio_set_speed(comm_dev, miso_bit, GPIO_speed_100MHz);
108 
109  /* Configure MOSI pin */
110  gpio_set_mode(comm_dev, mosi_bit, GPIO_AF_OUTPUT_PP);
111  gpio_set_af_mode(comm_dev, mosi_bit, dev->afio);
112  gpio_set_speed(comm_dev, mosi_bit, GPIO_speed_100MHz);
113 }
114 
116  const gpio_dev *comm_dev,
117  uint8_t sck_bit,
118  uint8_t miso_bit,
119  uint8_t mosi_bit) {
120 
121  /* Configure SCK pin */
122  gpio_set_mode(comm_dev, sck_bit, GPIO_INPUT_FLOATING);
123  /* Configure MISO pin */
124  gpio_set_mode(comm_dev, miso_bit, GPIO_AF_OUTPUT_PP);
125  /* Configure MOSI pin */
126  gpio_set_mode(comm_dev, mosi_bit, GPIO_INPUT_FLOATING);
127 }
128 
129 /*
130  * SPI auxiliary routines
131  */
132 void spi_reconfigure(const spi_dev *dev, uint8_t ismaster, uint16_t baudPrescaler, uint16_t bitorder, uint8_t mode) {
133  SPI_InitTypeDef SPI_InitStructure;
134 
135  memset(dev->state, 0, sizeof(spi_state));
136 
138 
139  spi_init(dev);
140 
142 
143  /* Enable the SPI clock */
144  if (dev->SPIx == SPI1)
145  RCC_APB2PeriphClockCmd(dev->clock, ENABLE);
146  else if (dev->SPIx == SPI2)
147  RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE);
148  else
149  RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI3, ENABLE);
150 
151  /* SPI configuration */
152  SPI_StructInit(&SPI_InitStructure);
153  SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
154  SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
155 
156  switch(mode) {
157  case SPI_MODE_0:
158  SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;
159  SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;
160  break;
161  case SPI_MODE_1:
162  SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;
163  SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;
164  break;
165  case SPI_MODE_2:
166  SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;
167  SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;
168  break;
169  case SPI_MODE_3:
170  SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;
171  SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;
172  break;
173  default:
174  break;
175  }
176 
177 
178  SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
179  SPI_InitStructure.SPI_BaudRatePrescaler = baudPrescaler;
180  if (bitorder == LSBFIRST)
181  SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_LSB;
182  else
183  SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
184 
185  SPI_InitStructure.SPI_CRCPolynomial = 7;
186  if (ismaster)
187  SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
188  else
189  SPI_InitStructure.SPI_Mode = SPI_Mode_Slave;
190 
191  SPI_Init(dev->SPIx, &SPI_InitStructure);
192 
193  SPI_Cmd(dev->SPIx, ENABLE);
194 
195  uint32_t dly=1000;
196  while (SPI_I2S_GetFlagStatus(dev->SPIx, SPI_BIT_TXE) == RESET) {
197  dly--;
198  if(dly==0) break;
199  }
200 
201  (void) dev->SPIx->DR;
202 }
203 
204 
205 void spi_set_speed(const spi_dev *dev, uint16_t baudPrescaler) {
206 
207 #define BR_CLEAR_MASK 0xFFC7
208 
209  SPI_Cmd(dev->SPIx, DISABLE);
210 
211  dev->SPIx->CR1 = (dev->SPIx->CR1 & BR_CLEAR_MASK) | baudPrescaler;
212 
213  SPI_Cmd(dev->SPIx, ENABLE);
214 }
215 
216 
217 
218 // Transmit command and/or receive result in bidirectional master mode
220  const uint8_t *txbuf,
221  uint16_t txcount,
222  uint8_t *rxbuf,
223  uint16_t rxcount)
224 {
225  uint16_t txc_in=txcount;
226 
227  // Transfer command data out
228 
229  while (txcount--){
230  while (!(dev->SPIx->SR & SPI_BIT_TXE)){ // just for case
231  if(!spi_is_busy(dev) ) break;
232  }
233  dev->SPIx->DR = *txbuf++;
234  uint16_t dly=1000; // ~20uS so byte already transferred
235  while (!(dev->SPIx->SR & SPI_BIT_RXNE)) {
236  if(--dly==0) break;
237  }
238  (void) dev->SPIx->DR; // read out unneeded data
239  }
240 
241  if(txc_in && rxcount) delay_ns100(5); // small delay between TX and RX, to give the chip time to think over domestic affairs
242 
243  // Transfer response data in
244  while (rxcount--){
245  while (!(dev->SPIx->SR & SPI_BIT_TXE));
246  dev->SPIx->DR = 0xFF;
247  uint16_t dly=1000;
248  while (!(dev->SPIx->SR & SPI_BIT_RXNE)) {
249  if(--dly==0) break;
250  }
251  *rxbuf++ = dev->SPIx->DR;
252  }
253 
254  // Wait until the transfer is complete - to not disable CS too early
255  uint32_t dly=3000;
256  while (dev->SPIx->SR & SPI_BIT_BSY){ // but datasheet prohibits this usage
257  dly--;
258  if(dly==0) break;
259  }
260 
261  return 0;
262 }
263 
264 
265 static void isr_handler(const spi_dev *dev){
266  NVIC_ClearPendingIRQ(dev->irq);
267  if(dev->state->handler) revo_call_handler(dev->state->handler, dev->SPIx->SR);
268  else { // disable interrupts
270  }
271 }
272 
273 void SPI1_IRQHandler();
274 void SPI2_IRQHandler();
275 void SPI3_IRQHandler();
276 
278  isr_handler(&spi1);
279 }
280 
282  isr_handler(&spi2);
283 }
284 
286  isr_handler(&spi3);
287 }
#define SPI_BIT_RXNE
Definition: spi.h:82
IRQn_Type irq
Definition: spi.h:32
Definition: spi.h:55
Definition: spi.h:59
const spi_dev *const _SPI2
Definition: spi.c:43
void SPI2_IRQHandler()
Definition: spi.c:281
static const spi_dev spi1
Definition: spi.c:23
static void spi_peripheral_disable(const spi_dev *dev)
Disable a SPI peripheral.
Definition: spi.h:138
void spi_set_speed(const spi_dev *dev, uint16_t baudPrescaler)
Definition: spi.c:205
void spi_init(const spi_dev *dev)
Initialize and reset a SPI device.
Definition: spi.c:57
Handler handler
Definition: spi.h:22
void gpio_set_mode(const gpio_dev *const dev, uint8_t pin, gpio_pin_mode mode)
Definition: gpio_hal.c:125
#define SPI_BIT_TXE
Definition: spi.h:83
uint8_t afio
Definition: spi.h:31
uint16_t clock
Definition: spi.h:33
#define DMA_CR_CH0
Definition: dma.h:98
int spimaster_transfer(const spi_dev *dev, const uint8_t *txbuf, uint16_t txcount, uint8_t *rxbuf, uint16_t rxcount)
Definition: spi.c:219
const spi_dev *const _SPI3
Definition: spi.c:54
void SPI1_IRQHandler()
Definition: spi.c:277
Definition: spi.h:57
static AP_HAL::OwnPtr< AP_HAL::Device > dev
Definition: ICM20789.cpp:16
#define BR_CLEAR_MASK
void spi_gpio_slave_cfg(const spi_dev *dev, const gpio_dev *comm_dev, uint8_t sck_bit, uint8_t miso_bit, uint8_t mosi_bit)
Definition: spi.c:115
static void spi_disable_irq(const spi_dev *dev, spi_interrupt interrupt_flags)
Definition: spi.h:241
static void isr_handler(const spi_dev *dev)
Definition: spi.c:265
static uint8_t spi_is_busy(const spi_dev *dev)
Definition: spi.h:271
Definition: spi.h:43
#define DMA_CR_CH3
Definition: dma.h:101
static const spi_dev spi3
Definition: spi.c:45
Definition: spi.h:61
static const spi_dev spi2
Definition: spi.c:34
static spi_state spi1_state IN_CCM
Definition: spi.c:19
SPI_TypeDef * SPIx
Definition: spi.h:30
static void gpio_set_speed(const gpio_dev *const dev, uint8_t pin, GPIOSpeed_t gpio_speed)
Definition: gpio_hal.h:161
Definition: spi.h:21
const spi_dev *const _SPI1
Definition: spi.c:32
static void gpio_set_af_mode(const gpio_dev *const dev, uint8_t pin, uint8_t mode)
Definition: gpio_hal.h:102
spi_state * state
Definition: spi.h:35
static void delay_ns100(uint32_t us)
Definition: delay.h:36
void revo_call_handler(Handler h, uint32_t arg)
Definition: Scheduler.cpp:1420
void spi_foreach(void(*fn)(const spi_dev *))
Call a function on each SPI port.
Definition: spi.c:84
void SPI3_IRQHandler()
Definition: spi.c:285
Definition: spi.h:29
#define SPI_BIT_BSY
Definition: spi.h:87
void spi_gpio_master_cfg(const spi_dev *dev, const gpio_dev *comm_dev, uint8_t sck_bit, uint8_t miso_bit, uint8_t mosi_bit)
Configure and enable a SPI device as bus master.
Definition: spi.c:92
void spi_reconfigure(const spi_dev *dev, uint8_t ismaster, uint16_t baudPrescaler, uint16_t bitorder, uint8_t mode)
Definition: spi.c:132