Paparazzi UAS  v5.18.0_stable
Paparazzi is a free software Unmanned Aircraft System.
can_arch.c
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2012 Piotr Esden-Tempski <piotr@esden.net>
3  *
4  * This file is part of paparazzi.
5  *
6  * paparazzi is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2, or (at your option)
9  * any later version.
10  *
11  * paparazzi is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with paparazzi; see the file COPYING. If not, write to
18  * the Free Software Foundation, 59 Temple Place - Suite 330,
19  * Boston, MA 02111-1307, USA.
20  *
21  */
22 
30 #include <stdint.h>
31 #include <string.h>
32 
33 #include "mcu_periph/can_arch.h"
34 #include "mcu_periph/can.h"
35 
36 #include <libopencm3/stm32/rcc.h>
37 #include <libopencm3/stm32/gpio.h>
38 #include <libopencm3/stm32/can.h>
39 #include <libopencm3/cm3/nvic.h>
40 
41 #include "led.h"
42 
43 
44 #ifdef RTOS_PRIO
45 #define NVIC_USB_LP_CAN_RX0_IRQ_PRIO RTOS_PRIO+1
46 #else
47 #define NVIC_USB_LP_CAN_RX0_IRQ_PRIO 1
48 #define NVIC_CAN1_RX_IRQ_PRIO 1
49 #endif
50 
51 void _can_run_rx_callback(uint32_t id, uint8_t *buf, uint8_t len);
52 
53 bool can_initialized = false;
54 
55 void can_hw_init(void)
56 {
57 
58 
59 #ifdef STM32F1
60  /* Enable peripheral clocks. */
61  rcc_periph_clock_enable(RCC_AFIO);
62  rcc_periph_clock_enable(RCC_GPIOB);
63  rcc_periph_clock_enable(RCC_CAN1);
64 
65  /* Remap the gpio pin if necessary. */
66  AFIO_MAPR |= AFIO_MAPR_CAN1_REMAP_PORTB;
67 
68  /* Configure CAN pin: RX (input pull-up). */
69  gpio_set_mode(GPIO_BANK_CAN1_PB_RX, GPIO_MODE_INPUT,
70  GPIO_CNF_INPUT_PULL_UPDOWN, GPIO_CAN1_PB_RX);
71  gpio_set(GPIO_BANK_CAN1_PB_RX, GPIO_CAN1_PB_RX);
72 
73  /* Configure CAN pin: TX (output push-pull). */
74  gpio_set_mode(GPIO_BANK_CAN1_PB_TX, GPIO_MODE_OUTPUT_50_MHZ,
75  GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, GPIO_CAN1_PB_TX);
76 
77  /* NVIC setup. */
78  nvic_enable_irq(NVIC_USB_LP_CAN_RX0_IRQ);
79  nvic_set_priority(NVIC_USB_LP_CAN_RX0_IRQ, NVIC_USB_LP_CAN_RX0_IRQ_PRIO);
80 
81 #elif STM32F4
82 
83  /* Enable peripheral clocks. */
84  rcc_periph_clock_enable(RCC_GPIOB);
85  rcc_periph_clock_enable(RCC_CAN1);
86 
87  /* set up pins for CAN1TX & CAN1RX alternate function */
88  gpio_mode_setup(GPIOB, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO8 | GPIO9);
89  gpio_set_af(GPIOB, GPIO_AF9, GPIO8 | GPIO9);
90 
91  /* enable interrupts on RX0 FIFO */
92  nvic_enable_irq(NVIC_CAN1_RX0_IRQ);
93  nvic_set_priority(NVIC_CAN1_RX0_IRQ, NVIC_CAN1_RX_IRQ_PRIO);
94 
95 #endif
96  /* Reset CAN. */
97  can_reset(CAN1);
98 
99  /* CAN cell init.
100  * For time quanta calculation see STM32 reference manual
101  * section 24.7.7 "Bit timing" page 645
102  *
103  * To talk to CSC using LPC mcu we need a baud rate of 375kHz
104  * The APB1 runs at 36MHz therefor we select a prescaler of 12
105  * resulting in time quanta frequency of 36MHz / 12 = 3MHz
106  *
107  * As the Bit time is combined of 1tq for SYNC_SEG, TS1tq for bit
108  * segment 1 and TS2tq for bit segment 2:
109  * BITtq = 1tq + TS1tq + TS2tq
110  *
111  * We can choose to use TS1 = 3 and TS2 = 4 getting
112  * 1tq + 3tq + 4tq = 8tq per bit therefor a bit frequency is
113  * 3MHZ / 8 = 375kHz
114  *
115  * Maximum baud rate of CAN is 1MHz so we can choose to use
116  * prescaler of 2 resulting in a quanta frequency of 36MHz / 2 = 18Mhz
117  *
118  * So we need to devide the frequency by 18. This can be accomplished
119  * using TS1 = 10 and TS2 = 7 resulting in:
120  * 1tq + 10tq + 7tq = 18tq
121  *
122  * NOTE: Although it is out of spec I managed to have CAN run at 2MBit
123  * Just decrease the prescaler to 1. It worked for me(tm) (esden)
124  */
125  if (can_init(CAN1,
126  false, /* TTCM: Time triggered comm mode? */
127  true, /* ABOM: Automatic bus-off management? */
128  false, /* AWUM: Automatic wakeup mode? */
129  false, /* NART: No automatic retransmission? */
130  false, /* RFLM: Receive FIFO locked mode? */
131  false, /* TXFP: Transmit FIFO priority? */
132 #ifdef STM32F1
133  CAN_BTR_SJW_1TQ,
134  CAN_BTR_TS1_10TQ,
135  CAN_BTR_TS2_7TQ,
136 #elif STM32F4
137  CAN_BTR_SJW_1TQ,
138  CAN_BTR_TS1_14TQ,
139  CAN_BTR_TS2_6TQ,
140 #endif
141  2, /* BRP+1: Baud rate prescaler */
142  false, /* loopback mode */
143  false)) { /* silent mode */
144  /* TODO we need something somewhere where we can leave a note
145  * that CAN was unable to initialize. Just like any other
146  * driver should...
147  */
148 
149  can_reset(CAN1);
150 
151  return;
152  }
153 
154  /* CAN filter 0 init. */
155  can_filter_id_mask_32bit_init(CAN1,
156  0, /* Filter ID */
157  0, /* CAN ID */
158  0, /* CAN ID mask */
159  0, /* FIFO assignment (here: FIFO0) */
160  true); /* Enable the filter. */
161 
162  /* Enable CAN RX interrupt. */
163  can_enable_irq(CAN1, CAN_IER_FMPIE0);
164 
165  /* Remember that we succeeded to initialize. */
166  can_initialized = true;
167 }
168 
169 int can_hw_transmit(uint32_t id, const uint8_t *buf, uint8_t len)
170 {
171 
172  if (!can_initialized) {
173  return -2;
174  }
175 
176  if (len > 8) {
177  return -1;
178  }
179 
180 
181  /* FIXME: we are discarding the const qualifier for buf here.
182  * We should probably fix libopencm3 to actually have the
183  * const qualifier too...
184  */
185  return can_transmit(CAN1,
186  id, /* (EX/ST)ID: CAN ID */
187 #ifdef USE_CAN_EXT_ID
188  true, /* IDE: CAN ID extended */
189 #else
190  false, /* IDE: CAN ID not extended */
191 #endif
192  false, /* RTR: Request transmit? */
193  len, /* DLC: Data length */
194  (uint8_t *)buf);
195 }
196 #ifdef STM32F1
197 void usb_lp_can_rx0_isr(void)
198 {
199  uint32_t id;
200  uint8_t fmi;
201  bool ext, rtr;
202  uint8_t length, data[8];
203  uint16_t timestamp;
204 
205  can_receive(CAN1,
206  0, /* FIFO: 0 */
207  false, /* Release */
208  &id,
209  &ext,
210  &rtr,
211  &fmi,
212  &length,
213  data,
214  &timestamp);
215 
216  _can_run_rx_callback(id, data, length);
217 
218  can_fifo_release(CAN1, 0);
219 }
220 #elif STM32F4
221 void can1_rx0_isr(void){
222  uint32_t id;
223  uint8_t fmi;
224  bool ext, rtr;
225  uint8_t length, data[8];
226  uint16_t timestamp;
227 
228  can_receive(CAN1,
229  0, /* FIFO: 0 */
230  false, /* Release */
231  &id,
232  &ext,
233  &rtr,
234  &fmi,
235  &length,
236  data,
237  &timestamp);
238 
239  _can_run_rx_callback(id, data, length);
240 
241  can_fifo_release(CAN1, 0);
242 }
243 #endif
uint16_t
unsigned short uint16_t
Definition: types.h:16
GPIO9
#define GPIO9
Definition: gpio_def.h:40
uint32_t
unsigned long uint32_t
Definition: types.h:18
GPIOB
#define GPIOB
Definition: gpio_arch.h:37
CAN1
#define CAN1
Definition: LPC21xx.h:484
can_initialized
bool can_initialized
Definition: can_arch.c:53
can_arch.h
uint8_t
unsigned char uint8_t
Definition: types.h:14
led.h
arch independent LED (Light Emitting Diodes) API
can_hw_init
void can_hw_init(void)
Definition: can_arch.c:55
GPIO8
#define GPIO8
Definition: gpio_def.h:39
NVIC_USB_LP_CAN_RX0_IRQ_PRIO
#define NVIC_USB_LP_CAN_RX0_IRQ_PRIO
Definition: can_arch.c:47
can_hw_transmit
int can_hw_transmit(uint32_t id, const uint8_t *buf, uint8_t len)
Definition: can_arch.c:169
NVIC_CAN1_RX_IRQ_PRIO
#define NVIC_CAN1_RX_IRQ_PRIO
Definition: can_arch.c:48
can.h
gpio_set
static void gpio_set(ioportid_t port, uint16_t pin)
Set a gpio output to high level.
Definition: gpio_arch.h:98
GPIO_AF9
#define GPIO_AF9
Definition: gpio_def.h:73
_can_run_rx_callback
void _can_run_rx_callback(uint32_t id, uint8_t *buf, uint8_t len)
Definition: can.c:43