dRonin  adbada4
dRonin firmware
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
pios_spi.c
Go to the documentation of this file.
1 
22 /*
23  * This program is free software; you can redistribute it and/or modify
24  * it under the terms of the GNU General Public License as published by
25  * the Free Software Foundation; either version 3 of the License, or
26  * (at your option) any later version.
27  *
28  * This program is distributed in the hope that it will be useful, but
29  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
30  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
31  * for more details.
32  *
33  * You should have received a copy of the GNU General Public License along
34  * with this program; if not, see <http://www.gnu.org/licenses/>
35  */
36 #include <pios.h>
37 
38 #if defined(PIOS_INCLUDE_SPI)
39 
40 #include <pios_spi_priv.h>
41 
42 #if !defined(STM32F30X)
43 #define SPI_SendData8(regs,b) do { (regs)->DR = (b); } while (0)
44 #define SPI_ReceiveData8(regs) ((regs)->DR)
45 #endif
46 
47 typedef enum {
48  PIOS_SPI_PRESCALER_2 = 0,
49  PIOS_SPI_PRESCALER_4 = 1,
50  PIOS_SPI_PRESCALER_8 = 2,
51  PIOS_SPI_PRESCALER_16 = 3,
52  PIOS_SPI_PRESCALER_32 = 4,
53  PIOS_SPI_PRESCALER_64 = 5,
54  PIOS_SPI_PRESCALER_128 = 6,
55  PIOS_SPI_PRESCALER_256 = 7
56 } SPIPrescalerTypeDef;
57 
58 
59 static bool PIOS_SPI_validate(struct pios_spi_dev *com_dev)
60 {
61  /* Should check device magic here */
62  return (true);
63 }
64 
65 static struct pios_spi_dev *PIOS_SPI_alloc(void)
66 {
67  return (PIOS_malloc(sizeof(struct pios_spi_dev)));
68 }
69 
75 int32_t PIOS_SPI_Init(pios_spi_t *spi_id, const struct pios_spi_cfg *cfg)
76 {
77  uint32_t init_ssel = 0;
78 
79  PIOS_Assert(spi_id);
80  PIOS_Assert(cfg);
81  PIOS_Assert(cfg->init.SPI_Mode == SPI_Mode_Master);
82 
83  struct pios_spi_dev *spi_dev;
84 
85  spi_dev = (struct pios_spi_dev *) PIOS_SPI_alloc();
86  if (!spi_dev) goto out_fail;
87 
88  /* Bind the configuration to the device instance */
89  spi_dev->cfg = cfg;
90 
91  spi_dev->busy = PIOS_Semaphore_Create();
92 
93  switch (spi_dev->cfg->init.SPI_NSS) {
94  case SPI_NSS_Soft:
95  /* We're a master in soft NSS mode, make sure we see NSS high at all times. */
96  SPI_NSSInternalSoftwareConfig(spi_dev->cfg->regs, SPI_NSSInternalSoft_Set);
97  /* Init as many slave selects as the config advertises. */
98  init_ssel = spi_dev->cfg->slave_count;
99  break;
100 
101  case SPI_NSS_Hard:
102  /* only legal for single-slave config */
103  PIOS_Assert(spi_dev->cfg->slave_count == 1);
104  init_ssel = 1;
105  SPI_SSOutputCmd(spi_dev->cfg->regs, ENABLE);
106  break;
107 
108  default:
109  PIOS_Assert(0);
110  }
111 
112 #ifndef STM32F10X_MD
113  /* Initialize the GPIO pins */
114  /* note __builtin_ctz() due to the difference between GPIO_PinX and GPIO_PinSourceX */
115  if (spi_dev->cfg->remap) {
116  GPIO_PinAFConfig(spi_dev->cfg->sclk.gpio,
117  __builtin_ctz(spi_dev->cfg->sclk.init.GPIO_Pin),
118  spi_dev->cfg->remap);
119  GPIO_PinAFConfig(spi_dev->cfg->mosi.gpio,
120  __builtin_ctz(spi_dev->cfg->mosi.init.GPIO_Pin),
121  spi_dev->cfg->remap);
122  GPIO_PinAFConfig(spi_dev->cfg->miso.gpio,
123  __builtin_ctz(spi_dev->cfg->miso.init.GPIO_Pin),
124  spi_dev->cfg->remap);
125 
126  /* Only remap pins to SPI function if hardware slave select is
127  * used. */
128  if (spi_dev->cfg->init.SPI_NSS == SPI_NSS_Hard) {
129  for (uint32_t i = 0; i < init_ssel; i++) {
130  GPIO_PinAFConfig(spi_dev->cfg->ssel[i].gpio,
131  __builtin_ctz(spi_dev->cfg->ssel[i].init.GPIO_Pin),
132  spi_dev->cfg->remap);
133  }
134  }
135  }
136 #endif
137  GPIO_Init(spi_dev->cfg->sclk.gpio, (GPIO_InitTypeDef *) & (spi_dev->cfg->sclk.init));
138  GPIO_Init(spi_dev->cfg->mosi.gpio, (GPIO_InitTypeDef *) & (spi_dev->cfg->mosi.init));
139  GPIO_Init(spi_dev->cfg->miso.gpio, (GPIO_InitTypeDef *) & (spi_dev->cfg->miso.init));
140 
141  for (uint32_t i = 0; i < init_ssel; i++) {
142  /* Since we're driving the SSEL pin in software, ensure that the slave is deselected */
143  GPIO_SetBits(spi_dev->cfg->ssel[i].gpio, spi_dev->cfg->ssel[i].init.GPIO_Pin);
144  GPIO_Init(spi_dev->cfg->ssel[i].gpio, (GPIO_InitTypeDef *) & (spi_dev->cfg->ssel[i].init));
145  }
146 
147  /* Initialize the SPI block */
148  SPI_I2S_DeInit(spi_dev->cfg->regs);
149  SPI_Init(spi_dev->cfg->regs, (SPI_InitTypeDef *) & (spi_dev->cfg->init));
150  SPI_CalculateCRC(spi_dev->cfg->regs, DISABLE);
151 
152 #if defined(STM32F30X)
153  /* Configure the RX FIFO Threshold -- 8 bits */
154  SPI_RxFIFOThresholdConfig(spi_dev->cfg->regs, SPI_RxFIFOThreshold_QF);
155 #endif
156 
157  /* Enable SPI */
158  SPI_Cmd(spi_dev->cfg->regs, ENABLE);
159 
160  *spi_id = spi_dev;
161 
162  return (0);
163 
164 out_fail:
165  return (-1);
166 }
167 
168 int32_t PIOS_SPI_SetClockSpeed(pios_spi_t spi_dev, uint32_t spi_speed)
169 {
170  bool valid = PIOS_SPI_validate(spi_dev);
171  PIOS_Assert(valid);
172 
173  SPI_InitTypeDef SPI_InitStructure;
174 
175  SPIPrescalerTypeDef spi_prescaler;
176 
177  //SPI clock is different depending on the bus
178  uint32_t spiBusClock = PIOS_SYSCLK;
179 
180 #if defined(STM32F40_41xxx) || defined(STM32F446xx)
181  if(spi_dev->cfg->regs == SPI1)
182  spiBusClock = PIOS_SYSCLK / 2;
183  else
184  spiBusClock = PIOS_SYSCLK / 4;
185 #elif defined(STM32F30X)
186  // SPI1 runs half as a fast
187  if(spi_dev->cfg->regs == SPI1)
188  spiBusClock = PIOS_SYSCLK / 2;
189 #elif !defined(STM32F10X_MD)
190  // F1 not handled explicitly --- spiBusClock is right above
191 #error Unrecognized architecture
192 #endif
193 
194  //The needed prescaler for desired speed
195  float desiredPrescaler=(float) spiBusClock / spi_speed;
196 
197  //Choosing the existing prescaler nearest the desiredPrescaler
198  if(desiredPrescaler <= 2)
199  spi_prescaler = PIOS_SPI_PRESCALER_2;
200  else if(desiredPrescaler <= 4)
201  spi_prescaler = PIOS_SPI_PRESCALER_4;
202  else if(desiredPrescaler <= 8)
203  spi_prescaler = PIOS_SPI_PRESCALER_8;
204  else if(desiredPrescaler <= 16)
205  spi_prescaler = PIOS_SPI_PRESCALER_16;
206  else if(desiredPrescaler <= 32)
207  spi_prescaler = PIOS_SPI_PRESCALER_32;
208  else if(desiredPrescaler <= 64)
209  spi_prescaler = PIOS_SPI_PRESCALER_64;
210  else if(desiredPrescaler <= 128)
211  spi_prescaler = PIOS_SPI_PRESCALER_128;
212  else
213  spi_prescaler = PIOS_SPI_PRESCALER_256;
214 
215  /* Start with a copy of the default configuration for the peripheral */
216  SPI_InitStructure = spi_dev->cfg->init;
217 
218  /* Adjust the prescaler for the peripheral's clock */
219  SPI_InitStructure.SPI_BaudRatePrescaler = ((uint16_t) spi_prescaler & 7) << 3;
220 
221  /* Write back the new configuration */
222  SPI_Init(spi_dev->cfg->regs, &SPI_InitStructure);
223 
224  //return set speed
225  return spiBusClock >> (1 + spi_prescaler);
226 }
227 
228 int32_t PIOS_SPI_ClaimBus(pios_spi_t spi_dev)
229 {
230  bool valid = PIOS_SPI_validate(spi_dev);
231  PIOS_Assert(valid);
232 
233  if (PIOS_Semaphore_Take(spi_dev->busy, PIOS_SEMAPHORE_TIMEOUT_MAX) != true)
234  return -1;
235 
236  return 0;
237 }
238 
239 int32_t PIOS_SPI_ReleaseBus(pios_spi_t spi_dev)
240 {
241  bool valid = PIOS_SPI_validate(spi_dev);
242  PIOS_Assert(valid);
243 
244  PIOS_Semaphore_Give(spi_dev->busy);
245 
246  return 0;
247 }
248 
249 int32_t PIOS_SPI_RC_PinSet(pios_spi_t spi_dev, uint32_t slave_id, bool pin_value)
250 {
251  bool valid = PIOS_SPI_validate(spi_dev);
252  PIOS_Assert(valid);
253  PIOS_Assert(slave_id <= spi_dev->cfg->slave_count);
254 
255  if (pin_value) {
256  GPIO_SetBits(spi_dev->cfg->ssel[slave_id].gpio, spi_dev->cfg->ssel[slave_id].init.GPIO_Pin);
257  } else {
258  GPIO_ResetBits(spi_dev->cfg->ssel[slave_id].gpio, spi_dev->cfg->ssel[slave_id].init.GPIO_Pin);
259  }
260 
261  return 0;
262 }
263 
264 uint8_t PIOS_SPI_TransferByte(pios_spi_t spi_dev, uint8_t b)
265 {
266  bool valid = PIOS_SPI_validate(spi_dev);
267  PIOS_Assert(valid);
268 
269  uint8_t rx_byte;
270 
271  /*
272  * Procedure taken from STM32F10xxx Reference Manual section 23.3.5
273  */
274 
275  /* Make sure the RXNE flag is cleared by reading the DR register */
276  SPI_ReceiveData8(spi_dev->cfg->regs);
277 
278  /* Wait until the TXE goes high */
279  while (SPI_I2S_GetFlagStatus(spi_dev->cfg->regs, SPI_I2S_FLAG_TXE) == RESET);
280 
281  /* Start the transfer */
282  SPI_SendData8(spi_dev->cfg->regs, b);
283 
284  /* Wait until there is a byte to read */
285  while (SPI_I2S_GetFlagStatus(spi_dev->cfg->regs, SPI_I2S_FLAG_RXNE) == RESET);
286 
287  /* Read the rx'd byte */
288  rx_byte = SPI_ReceiveData8(spi_dev->cfg->regs);
289 
290  /* Wait until the TXE goes high */
291  while (!(spi_dev->cfg->regs->SR & SPI_I2S_FLAG_TXE));
292 
293  /* Wait for SPI transfer to have fully completed */
294  while (spi_dev->cfg->regs->SR & SPI_I2S_FLAG_BSY);
295 
296  /* Return received byte */
297  return rx_byte;
298 }
299 
312 static int32_t SPI_PIO_TransferBlock(pios_spi_t spi_dev,
313  const uint8_t *send_buffer, uint8_t *receive_buffer, uint16_t len)
314 {
315  uint8_t b;
316 
317  bool valid = PIOS_SPI_validate(spi_dev);
318  PIOS_Assert(valid);
319 
320  while (len--) {
321  /* get the byte to send */
322  b = send_buffer ? *(send_buffer++) : 0xff;
323 
324  /* Wait until the TXE goes high */
325  while (SPI_I2S_GetFlagStatus(spi_dev->cfg->regs, SPI_I2S_FLAG_TXE) == RESET);
326 
327  /* Start the transfer */
328  SPI_SendData8(spi_dev->cfg->regs, b);
329 
330  /* Wait until there is a byte to read */
331  while (SPI_I2S_GetFlagStatus(spi_dev->cfg->regs, SPI_I2S_FLAG_RXNE) == RESET);
332 
333  /* Read the rx'd byte */
334  b = SPI_ReceiveData8(spi_dev->cfg->regs);
335 
336  /* save the received byte */
337  if (receive_buffer)
338  *(receive_buffer++) = b;
339  }
340 
341  /* Wait for SPI transfer to have fully completed */
342  while (spi_dev->cfg->regs->SR & SPI_I2S_FLAG_BSY);
343 
344  return 0;
345 }
346 
347 int32_t PIOS_SPI_TransferBlock(pios_spi_t spi_dev, const uint8_t *send_buffer,
348  uint8_t *receive_buffer, uint16_t len)
349 {
350  return SPI_PIO_TransferBlock(spi_dev, send_buffer, receive_buffer, len);
351 }
352 
353 #endif
354 
struct stm32_gpio mosi
Definition: pios_spi_priv.h:49
#define PIOS_SEMAPHORE_TIMEOUT_MAX
Main PiOS header to include all the compiled in PiOS options.
GPIO_InitTypeDef init
Definition: pios_stm32.h:61
SPI private definitions.
int32_t PIOS_SPI_RC_PinSet(pios_spi_t spi_dev, uint32_t slave_id, bool pin_value)
GPIO_TypeDef * gpio
Definition: pios_stm32.h:60
int32_t PIOS_SPI_ClaimBus(pios_spi_t spi_dev)
void * PIOS_malloc(size_t size)
Definition: pios_heap.c:125
struct stm32_gpio ssel[]
Definition: pios_spi_priv.h:56
static struct flyingpicmd_cfg_fa cfg
Definition: main.c:49
SPI_TypeDef * regs
Definition: pios_spi_priv.h:44
struct pios_semaphore * PIOS_Semaphore_Create(void)
Creates a binary semaphore.
uint8_t PIOS_SPI_TransferByte(pios_spi_t spi_dev, uint8_t b)
int32_t PIOS_SPI_SetClockSpeed(pios_spi_t spi_dev, uint32_t speed)
int32_t PIOS_SPI_Init(pios_spi_t *spi_dev, const struct pios_spi_cfg *cfg)
int32_t PIOS_SPI_TransferBlock(pios_spi_t spi_dev, const uint8_t *send_buffer, uint8_t *receive_buffer, uint16_t len)
uint8_t i
Definition: msp_messages.h:97
bool PIOS_Semaphore_Give(struct pios_semaphore *sema)
Gives binary semaphore.
const struct pios_spi_cfg * cfg
Definition: pios_spi_priv.h:39
uint32_t slave_count
Definition: pios_spi_priv.h:50
struct stm32_gpio sclk
Definition: pios_spi_priv.h:47
bool PIOS_Semaphore_Take(struct pios_semaphore *sema, uint32_t timeout_ms)
Takes binary semaphore.
#define PIOS_SYSCLK
Definition: pios_board.h:143
uint32_t remap
Definition: pios_spi_priv.h:45
int32_t PIOS_SPI_ReleaseBus(pios_spi_t spi_dev)
struct stm32_gpio miso
Definition: pios_spi_priv.h:48
SPI_InitTypeDef init
Definition: pios_spi_priv.h:46
#define PIOS_Assert(test)
Definition: pios_debug.h:52
struct pios_semaphore * busy
Definition: pios_spi_priv.h:40