dRonin  adbada4
dRonin firmware
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
pios_can.c
Go to the documentation of this file.
1 
15 /*
16  * This program is free software; you can redistribute it and/or modify
17  * it under the terms of the GNU General Public License as published by
18  * the Free Software Foundation; either version 3 of the License, or
19  * (at your option) any later version.
20  *
21  * This program is distributed in the hope that it will be useful, but
22  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
23  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
24  * for more details.
25  *
26  * You should have received a copy of the GNU General Public License along
27  * with this program; if not, see <http://www.gnu.org/licenses/>
28  */
29 
30 
31 #include "pios.h"
32 
33 #if defined(PIOS_INCLUDE_CAN)
34 
35 #include "pios_can_priv.h"
36 
37 /* Provide a COM driver */
38 static void PIOS_CAN_RegisterRxCallback(uintptr_t can_id, pios_com_callback rx_in_cb, uintptr_t context);
39 static void PIOS_CAN_RegisterTxCallback(uintptr_t can_id, pios_com_callback tx_out_cb, uintptr_t context);
40 static void PIOS_CAN_TxStart(uintptr_t can_id, uint16_t tx_bytes_avail);
41 static void PIOS_CAN_RxStart(uintptr_t can_id, uint16_t rx_bytes_avail);
42 
43 const struct pios_com_driver pios_can_com_driver = {
44  .tx_start = PIOS_CAN_TxStart,
45  .rx_start = PIOS_CAN_RxStart,
46  .bind_tx_cb = PIOS_CAN_RegisterTxCallback,
47  .bind_rx_cb = PIOS_CAN_RegisterRxCallback,
48 };
49 
50 enum pios_can_dev_magic {
51  PIOS_CAN_DEV_MAGIC = 0x41fa834A,
52 };
53 
55 struct pios_can_dev {
56  enum pios_can_dev_magic magic;
57  const struct pios_can_cfg *cfg;
58  pios_com_callback rx_in_cb;
59  uintptr_t rx_in_context;
60  pios_com_callback tx_out_cb;
61  uintptr_t tx_out_context;
62 };
63 
64 // Local constants
65 #define CAN_COM_ID 0x11
66 #define MAX_SEND_LEN 8
67 
68 
69 static void PIOS_CAN_RxGeneric(void);
70 static void PIOS_CAN_TxGeneric(void);
71 
72 static bool PIOS_CAN_validate(struct pios_can_dev *can_dev)
73 {
74  return (can_dev->magic == PIOS_CAN_DEV_MAGIC);
75 }
76 
77 static struct pios_can_dev *PIOS_CAN_alloc(void)
78 {
79  struct pios_can_dev *can_dev;
80 
81  can_dev = (struct pios_can_dev *)PIOS_malloc(sizeof(*can_dev));
82  if (!can_dev) return(NULL);
83 
84  memset(can_dev, 0, sizeof(*can_dev));
85  can_dev->magic = PIOS_CAN_DEV_MAGIC;
86 
87  return(can_dev);
88 }
89 
91 static struct pios_can_dev *can_dev;
92 
99 int32_t PIOS_CAN_Init(uintptr_t *can_id, const struct pios_can_cfg *cfg)
100 {
101  PIOS_DEBUG_Assert(can_id);
102  PIOS_DEBUG_Assert(cfg);
103 
104  can_dev = (struct pios_can_dev *) PIOS_CAN_alloc();
105  if (!can_dev) goto out_fail;
106 
107  /* Bind the configuration to the device instance */
108  can_dev->cfg = cfg;
109 
110  /* Configure the CAN device */
111  if (can_dev->cfg->regs == CAN1) {
112  RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE);
113  } else {
114  RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE);
115  RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN2, ENABLE);
116  }
117 
118  /* Map pins to CAN function */
119  if (can_dev->cfg->remap) {
120  if (can_dev->cfg->rx.gpio != 0)
121  GPIO_PinAFConfig(can_dev->cfg->rx.gpio,
122  can_dev->cfg->rx.pin_source,
123  can_dev->cfg->remap);
124  if (can_dev->cfg->tx.gpio != 0)
125  GPIO_PinAFConfig(can_dev->cfg->tx.gpio,
126  can_dev->cfg->tx.pin_source,
127  can_dev->cfg->remap);
128  }
129 
130  /* Initialize the CAN Rx and Tx pins */
131  if (can_dev->cfg->rx.gpio != 0)
132  GPIO_Init(can_dev->cfg->rx.gpio, (GPIO_InitTypeDef *)&can_dev->cfg->rx.init);
133  if (can_dev->cfg->tx.gpio != 0)
134  GPIO_Init(can_dev->cfg->tx.gpio, (GPIO_InitTypeDef *)&can_dev->cfg->tx.init);
135 
136  *can_id = (uintptr_t)can_dev;
137 
138  CAN_DeInit(can_dev->cfg->regs);
139  CAN_Init(can_dev->cfg->regs, (CAN_InitTypeDef *)&can_dev->cfg->init);
140 
141  /* CAN filter init */
142  CAN_FilterInitTypeDef CAN_FilterInitStructure;
143  CAN_FilterInitStructure.CAN_FilterNumber = 0;
144  CAN_FilterInitStructure.CAN_FilterMode = CAN_FilterMode_IdMask;
145  CAN_FilterInitStructure.CAN_FilterScale = CAN_FilterScale_32bit;
146  CAN_FilterInitStructure.CAN_FilterIdHigh = 0x0000;
147  CAN_FilterInitStructure.CAN_FilterIdLow = 0x0000;
148  CAN_FilterInitStructure.CAN_FilterMaskIdHigh = 0x0000;
149  CAN_FilterInitStructure.CAN_FilterMaskIdLow = 0x0000;
150  CAN_FilterInitStructure.CAN_FilterFIFOAssignment = 1;
151 
152  CAN_FilterInitStructure.CAN_FilterActivation = ENABLE;
153  CAN_FilterInit(&CAN_FilterInitStructure);
154 
155  // Enable the receiver IRQ
156  NVIC_Init((NVIC_InitTypeDef*) &can_dev->cfg->rx_irq.init);
157  NVIC_Init((NVIC_InitTypeDef*) &can_dev->cfg->tx_irq.init);
158 
159  return(0);
160 
161 out_fail:
162  return(-1);
163 }
164 
165 static void PIOS_CAN_RxStart(uintptr_t can_id, uint16_t rx_bytes_avail)
166 {
167  struct pios_can_dev *can_dev = (struct pios_can_dev *)can_id;
168 
169  bool valid = PIOS_CAN_validate(can_dev);
170  PIOS_Assert(valid);
171 
172  CAN_ITConfig(can_dev->cfg->regs, CAN_IT_FMP1, ENABLE);
173 }
174 
175 static void PIOS_CAN_TxStart(uintptr_t can_id, uint16_t tx_bytes_avail)
176 {
177  struct pios_can_dev *can_dev = (struct pios_can_dev *)can_id;
178 
179  bool valid = PIOS_CAN_validate(can_dev);
180  PIOS_Assert(valid);
181 
182  CAN_ITConfig(can_dev->cfg->regs, CAN_IT_TME, ENABLE);
183 
184  PIOS_CAN_TxGeneric();
185 }
186 
187 static void PIOS_CAN_RegisterRxCallback(uintptr_t can_id, pios_com_callback rx_in_cb, uintptr_t context)
188 {
189  struct pios_can_dev *can_dev = (struct pios_can_dev *)can_id;
190 
191  bool valid = PIOS_CAN_validate(can_dev);
192  PIOS_Assert(valid);
193 
194  /*
195  * Order is important in these assignments since ISR uses _cb
196  * field to determine if it's ok to dereference _cb and _context
197  */
198  can_dev->rx_in_context = context;
199  can_dev->rx_in_cb = rx_in_cb;
200 }
201 
202 static void PIOS_CAN_RegisterTxCallback(uintptr_t can_id, pios_com_callback tx_out_cb, uintptr_t context)
203 {
204  struct pios_can_dev *can_dev = (struct pios_can_dev *)can_id;
205 
206  bool valid = PIOS_CAN_validate(can_dev);
207  PIOS_Assert(valid);
208 
209  /*
210  * Order is important in these assignments since ISR uses _cb
211  * field to determine if it's ok to dereference _cb and _context
212  */
213  can_dev->tx_out_context = context;
214  can_dev->tx_out_cb = tx_out_cb;
215 }
216 
218 static uint32_t pios_can_message_stdid[PIOS_CAN_LAST] = {
219  [PIOS_CAN_GIMBAL] = 0x130,
220 };
221 
223 static struct pios_queue *pios_can_queues[PIOS_CAN_LAST];
224 
229 static bool process_received_message(CanRxMsg message)
230 {
231  // Look for a known message that matches this CAN StdId
232  uint32_t msg_id;
233  for (msg_id = 0; msg_id < PIOS_CAN_LAST && pios_can_message_stdid[msg_id] != message.StdId; msg_id++);
234 
235  // If StdId is not one of the known messages, bail out
236  if (msg_id == PIOS_CAN_LAST)
237  return false;
238 
239  // Get the queue for this message and send the data
240  struct pios_queue *queue = pios_can_queues[msg_id];
241  if (queue == NULL)
242  return false;
243 
244  bool woken = false;
245  PIOS_Queue_Send_FromISR(queue, message.Data, &woken);
246 
247  return woken;
248 }
249 
256 struct pios_queue * PIOS_CAN_RegisterMessageQueue(uintptr_t id, enum pios_can_messages msg_id)
257 {
258  // Fetch the size of this message type or error if unknown
259  uint32_t bytes;
260  switch(msg_id) {
261  case PIOS_CAN_GIMBAL:
262  bytes = sizeof(struct pios_can_gimbal_message);
263  break;
264  default:
265  return NULL;
266  }
267 
268  // Return existing queue if created
269  if (pios_can_queues[msg_id] != NULL)
270  return pios_can_queues[msg_id];
271 
272  // Create a queue that can manage the data message size
273  struct pios_queue *queue;
274  queue = PIOS_Queue_Create(2, bytes);
275  if (queue == NULL)
276  return NULL;
277 
278  // Store the queue handle for the driver
279  pios_can_queues[msg_id] = queue;
280 
281  return queue;
282 }
283 
284 // Rx handlers
285 void CAN1_RX0_IRQHandler(void)
286 {
288  PIOS_CAN_RxGeneric();
290 }
291 void CAN1_RX1_IRQHandler(void)
292 {
294  PIOS_CAN_RxGeneric();
296 }
297 void CAN2_RX0_IRQHandler(void)
298 {
300  PIOS_CAN_RxGeneric();
302 }
303 void CAN2_RX1_IRQHandler(void)
304 {
306  PIOS_CAN_RxGeneric();
308 }
309 
310 // Tx handlers
311 void CAN1_TX_IRQHandler(void)
312 {
314  PIOS_CAN_TxGeneric();
316 }
317 void CAN2_TX_IRQHandler(void)
318 {
320  PIOS_CAN_TxGeneric();
322 }
323 
329 static void PIOS_CAN_RxGeneric(void)
330 {
331  CAN_ClearITPendingBit(can_dev->cfg->regs, CAN_IT_FMP1);
332 
333  bool valid = PIOS_CAN_validate(can_dev);
334  PIOS_Assert(valid);
335 
336  CanRxMsg RxMessage;
337  CAN_Receive(CAN1, CAN_FIFO1, &RxMessage);
338 
339  if (RxMessage.StdId == CAN_COM_ID) {
340  // TODO: remove this need_yield/woken pattern when f1 is on chibios
341  bool rx_need_yield;
342  if (can_dev->rx_in_cb) {
343  (void) (can_dev->rx_in_cb)(can_dev->rx_in_context, RxMessage.Data, RxMessage.DLC, NULL, &rx_need_yield);
344  }
345  } else {
346  process_received_message(RxMessage);
347  }
348 }
349 
353 static void PIOS_CAN_TxGeneric(void)
354 {
355  CAN_ClearITPendingBit(can_dev->cfg->regs, CAN_IT_TME);
356 
357  bool valid = PIOS_CAN_validate(can_dev);
358  PIOS_Assert(valid);
359 
360  bool tx_need_yield = false;
361 
362  if (can_dev->tx_out_cb) {
363 
364  // Prepare CAN message structure
365  CanTxMsg msg;
366  msg.StdId = CAN_COM_ID;
367  msg.ExtId = 0;
368  msg.IDE = CAN_ID_STD;
369  msg.RTR = CAN_RTR_DATA;
370  msg.DLC = (can_dev->tx_out_cb)(can_dev->tx_out_context, msg.Data, MAX_SEND_LEN, NULL, &tx_need_yield);
371 
372  // Send message and get mailbox number
373  if (msg.DLC > 0) {
374  CAN_Transmit(can_dev->cfg->regs, &msg);
375  } else {
376  CAN_ITConfig(can_dev->cfg->regs, CAN_IT_TME, DISABLE);
377  }
378 
379  // TODO: deal with failure to send and keep the message to retransmit
380  }
381 }
382 
383 
391 int32_t PIOS_CAN_TxData(uintptr_t id, enum pios_can_messages msg_id, uint8_t *data)
392 {
393  // Fetch the size of this message type or error if unknown
394  uint32_t bytes;
395  switch(msg_id) {
396  case PIOS_CAN_GIMBAL:
397  bytes = sizeof(struct pios_can_gimbal_message);
398  break;
399  default:
400  return -1;
401  }
402 
403  // Look up the CAN BUS Standard ID for this message type
404  uint32_t std_id = pios_can_message_stdid[msg_id];
405 
406  // Format and send the message
407  CanTxMsg msg;
408  msg.StdId = std_id & 0x7FF;
409  msg.ExtId = 0;
410  msg.IDE = CAN_ID_STD;
411  msg.RTR = CAN_RTR_DATA;
412  msg.DLC = (bytes > 8) ? 8 : bytes;
413  memcpy(msg.Data, data, msg.DLC);
414  CAN_Transmit(can_dev->cfg->regs, &msg);
415 
416  return msg.DLC;
417 }
418 
419 
420 #endif /* PIOS_INCLUDE_CAN */
421 
struct pios_queue * PIOS_Queue_Create(size_t queue_length, size_t item_size)
Definition: pios_queue.c:47
Main PiOS header to include all the compiled in PiOS options.
bool PIOS_Queue_Send_FromISR(struct pios_queue *queuep, const void *itemp, bool *wokenp)
Definition: pios_queue.c:163
#define PIOS_DEBUG_Assert(test)
Definition: pios_debug.h:51
#define PIOS_IRQ_Epilogue()
Definition: pios_irq.h:46
#define CAN1_TX_IRQHandler
void * PIOS_malloc(size_t size)
Definition: pios_heap.c:125
PiOS CAN interface header.
pios_can_messages
The set of CAN messages.
Definition: pios_can.h:36
uint8_t bytes[2]
Definition: storm32bgc.c:156
uint8_t data[XFER_BYTES_PER_PACKET]
Definition: bl_messages.h:129
#define CAN2_RX0_IRQHandler
static struct flyingpicmd_cfg_fa cfg
Definition: main.c:49
#define CAN1_RX1_IRQHandler
#define CAN1_RX0_IRQHandler
int32_t PIOS_CAN_TxData(uintptr_t id, enum pios_can_messages, uint8_t *data)
Transmit a data message with a particular message ID.
int32_t PIOS_CAN_Init(uintptr_t *id, const struct pios_can_cfg *cfg)
struct pios_queue * PIOS_CAN_RegisterMessageQueue(uintptr_t id, enum pios_can_messages msg_id)
Get a queue to receive messages of a particular message ID.
const struct pios_com_driver pios_can_com_driver
uint32_t magic
Message to tell gimbal the desired setpoint and FC state.
Definition: pios_can.h:42
#define PIOS_IRQ_Prologue()
Definition: pios_irq.h:45
static struct pios_queue * queue
Definition: actuator.c:82
#define CAN2_TX_IRQHandler
#define CAN2_RX1_IRQHandler
#define PIOS_Assert(test)
Definition: pios_debug.h:52
void(* tx_start)(uintptr_t id, uint16_t tx_bytes_avail)
Definition: pios_com.h:45
uint16_t(* pios_com_callback)(uintptr_t context, uint8_t *buf, uint16_t buf_len, uint16_t *headroom, bool *task_woken)
Definition: pios_com.h:41