Paparazzi UAS  v7.0_unstable
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(0, /* Filter ID */
156  0, /* CAN ID */
157  0, /* CAN ID mask */
158  0, /* FIFO assignment (here: FIFO0) */
159  true); /* Enable the filter. */
160 
161  /* Enable CAN RX interrupt. */
162  can_enable_irq(CAN1, CAN_IER_FMPIE0);
163 
164  /* Remember that we succeeded to initialize. */
165  can_initialized = true;
166 }
167 
168 int can_hw_transmit(uint32_t id, const uint8_t *buf, uint8_t len)
169 {
170 
171  if (!can_initialized) {
172  return -2;
173  }
174 
175  if (len > 8) {
176  return -1;
177  }
178 
179 
180  /* FIXME: we are discarding the const qualifier for buf here.
181  * We should probably fix libopencm3 to actually have the
182  * const qualifier too...
183  */
184  return can_transmit(CAN1,
185  id, /* (EX/ST)ID: CAN ID */
186 #ifdef USE_CAN_EXT_ID
187  true, /* IDE: CAN ID extended */
188 #else
189  false, /* IDE: CAN ID not extended */
190 #endif
191  false, /* RTR: Request transmit? */
192  len, /* DLC: Data length */
193  (uint8_t *)buf);
194 }
195 #ifdef STM32F1
196 void usb_lp_can_rx0_isr(void)
197 {
198  uint32_t id;
199  uint8_t fmi;
200  bool ext, rtr;
201  uint8_t length, data[8];
202  uint16_t timestamp;
203 
204  can_receive(CAN1,
205  0, /* FIFO: 0 */
206  false, /* Release */
207  &id,
208  &ext,
209  &rtr,
210  &fmi,
211  &length,
212  data,
213  &timestamp);
214 
215  _can_run_rx_callback(id, data, length);
216 
217  can_fifo_release(CAN1, 0);
218 }
219 #elif STM32F4
220 void can1_rx0_isr(void){
221  uint32_t id;
222  uint8_t fmi;
223  bool ext, rtr;
224  uint8_t length, data[8];
225  uint16_t timestamp;
226 
227  can_receive(CAN1,
228  0, /* FIFO: 0 */
229  false, /* Release */
230  &id,
231  &ext,
232  &rtr,
233  &fmi,
234  &length,
235  data,
236  &timestamp);
237 
238  _can_run_rx_callback(id, data, length);
239 
240  can_fifo_release(CAN1, 0);
241 }
242 #endif
void _can_run_rx_callback(uint32_t id, uint8_t *buf, uint8_t len)
Definition: can.c:43
#define NVIC_CAN1_RX_IRQ_PRIO
Definition: can_arch.c:48
bool can_initialized
Definition: can_arch.c:53
#define NVIC_USB_LP_CAN_RX0_IRQ_PRIO
Definition: can_arch.c:47
int can_hw_transmit(uint32_t id, const uint8_t *buf, uint8_t len)
Definition: can_arch.c:168
void can_hw_init(void)
Definition: can_arch.c:55
Handling of CAN hardware for STM32.
static void gpio_set(ioportid_t port, uint16_t pin)
Set a gpio output to high level.
Definition: gpio_arch.h:104
#define GPIO_AF9
Definition: gpio_def.h:73
#define GPIO8
Definition: gpio_def.h:39
#define GPIO9
Definition: gpio_def.h:40
arch independent LED (Light Emitting Diodes) API
#define GPIOB
Definition: gpio_arch.h:35
unsigned short uint16_t
Typedef defining 16 bit unsigned short type.
Definition: vl53l1_types.h:88
unsigned int uint32_t
Typedef defining 32 bit unsigned int type.
Definition: vl53l1_types.h:78
unsigned char uint8_t
Typedef defining 8 bit unsigned char type.
Definition: vl53l1_types.h:98