Loading...
Searching...
No Matches
can.c
1/***********************************************************************************
2 * @file can.c *
3 * @author Matt Ricci *
4 * @brief Brief description of the file's purpose. *
5 * *
6 * @todo Cleanup CAN interface header and implementation. *
7 ***********************************************************************************/
8
9#include "can.h"
10
11#include "stdbool.h"
12#include "stddef.h"
13
14#include "gpiopin.h"
15
16static void _CAN_init(CAN_TypeDef *, CAN_Config *);
17
18/* =============================================================================== */
30CAN_t CAN_init(CAN_TypeDef *interface, CAN_Config *config) {
31 // Early return error struct if peripheral is NULL
32 if (interface == NULL)
33 return (CAN_t){.interface = NULL};
34
35 // Initialise CAN struct with interface
36 CAN_t can = {.interface = interface};
37
38 // Update config and enable peripheral
39 CAN_updateConfig(&can, config);
40
41 // Initialise remaining parameters and methods
42 can.transmit = CAN_transmit;
43 can.receive = CAN_receive;
44 can.updateConfig = CAN_updateConfig;
45
46 return can;
47}
48
49// ALLOW FORMATTING
50#ifndef __DOXYGEN__
51
52/* =============================================================================== */
64static void _CAN_init(CAN_TypeDef *interface, CAN_Config *config) {
65 (void)interface;
66 (void)config;
67}
68
69#endif
70
71/* =============================================================================== */
80bool CAN_receive(CAN_t *can, CAN_Data *rxData) {
81
82 volatile uint32_t *fifo = (can->interface == CAN1) ? &CAN1->RF0R : &CAN2->RF1R;
83 uint8_t nFifo = (can->interface == CAN1) ? 0 : 1;
84
85 if (*fifo & CAN_RF0R_FMP0) {
86 // Read frame identifier and received data
87 rxData->id = (can->interface->sFIFOMailBox[nFifo].RIR & 0xFFE00040) >> 21;
88 rxData->data[0] = can->interface->sFIFOMailBox[nFifo].RDLR;
89 rxData->data[0] = can->interface->sFIFOMailBox[nFifo].RDHR;
90
91 // Update FIFO register
92 *fifo |= 1 << 5; // Release FIFO
93 *fifo &= ~CAN_RF0R_FOVR0; // Clear overrun flag
94 *fifo &= ~CAN_RF0R_FULL0; // Clear FIFO full flag
95 return true;
96 }
97
98 return false; // No frame to receive
99}
100
101/* =============================================================================== */
110uint8_t CAN_transmit(CAN_t *can, CAN_Data *txData) {
111
112 // Exit if no mailboxes are free
113 bool mailboxFree = can->interface->TSR & (0b111 << CAN_TSR_TME0_Pos);
114 if (!mailboxFree)
115 return 0;
116
117 uint8_t mailbox = (can->interface->TSR & CAN_TSR_CODE_Msk) >> CAN_TSR_CODE_Pos;
118
119 // Set frame data
120 can->interface->sTxMailBox[mailbox].TDHR = txData->data[1];
121 can->interface->sTxMailBox[mailbox].TDLR = txData->data[0];
122 can->interface->sTxMailBox[mailbox].TDTR = txData->length;
123
124 /* Set frame identifier */
125 can->interface->sTxMailBox[mailbox].TIR =
126 (txData->id <= CAN_STID_MAX) // Set id in:
127 ? (txData->id << CAN_TI0R_STID_Pos) // STID if within range
128 : (txData->id << CAN_TI0R_EXID_Pos); // Otherwise in EXID
129
130 // Request transmission
131 can->interface->sTxMailBox[mailbox].TIR |= CAN_TI0R_TXRQ;
132
133 // Add timer for timeout detection
134 while (1) {
135 if (can->interface->TSR & CAN_TSR_TXOK0)
136 return 0; // Success
137 else if (can->interface->TSR & CAN_TSR_TERR0) {
138 can->interface->TSR |= CAN_TSR_ABRQ0;
139 return 1; // TX error
140 }
141 }
142 return 255;
143}
144
145/* =============================================================================== */
157void CAN_updateConfig(CAN_t *can, CAN_Config *config) {
158 // Initialise config with default values if passed NULL.
159 if (config == NULL) {
160 // config = &CAN_CONFIG_DEFAULT;
161 }
162
163 // Update peripheral with new config
164 can->config = *config;
165
166 // Initialise CAN registers and enable peripheral
167 _CAN_init(can->interface, config);
168}
169
170/* =============================================================================== */
171
172void CANGPIO_config() {
173 GPIO_Config cfg = GPIO_CONFIG_DEFAULT;
174 cfg.afr = GPIO_AF9;
175 cfg.mode = GPIO_MODE_AF;
176 GPIOpin_init(GPIOA, GPIO_PIN11, &cfg);
177 GPIOpin_init(GPIOA, GPIO_PIN12, &cfg);
178}
179
180void CAN_Peripheral_config() {
181 CAN1->MCR |= CAN_MCR_RESET; // Reset CAN
182 while (CAN1->MCR & CAN_MCR_RESET); // Wait until reset
183
184 CAN1->MCR &= ~CAN_MCR_SLEEP; // Exit sleep
185 while (CAN1->MSR & CAN_MSR_SLAK);
186
187 CAN1->MCR |= CAN_MCR_INRQ; // Request initialisation mode
188 while (!(CAN1->MSR & CAN_MSR_INAK));
189
190 CAN1->BTR &= (uint32_t)~(0xC37F03FF); // clears all bit timing bits and disables loop back and silent mode
191 CAN1->BTR |= 0x003f000f; // enters the Bitrate as 125kb/s
192 CAN1->MCR |= (CAN_MCR_ABOM | CAN_MCR_AWUM); // Enable automatic bus-off management and wakeup
193
194 CAN1->FMR |= 0x1; // sets the filter initialisation to 'on'
195 CAN1->FM1R &= (uint32_t)~(0x1); // sets to mask mode filter
196 CAN1->FS1R |= 0x1; // sets to 32 bit mask, as the FR1/2 register is then for a single mask
197 CAN1->FA1R &= 0xF0000000; // disable all filters
198
199 CAN1->sFilterRegister[0].FR1 = 0; // assign filters so it will filter nothing
200 CAN1->sFilterRegister[0].FR2 = 0;
201
202 CAN1->FA1R |= 0x1; // enable the filter
203 CAN1->FMR &= (uint32_t)~(0x1); // take out of initialisation mode
204
205 CAN1->MCR &= ~CAN_MCR_INRQ; // Enter normal mode
206 while (CAN1->MSR & CAN_MSR_INAK); // Wait for normal mode
207
208 CAN1->IER |= CAN_IER_FMPIE0;
209}
GPIO_Mode mode
Pin I/O direction | (default GPIO_MODE_OUTPUT)
Definition gpiopin.h:139
GPIO_AF afr
Pin alternate function | (default GPIO_AF0)
Definition gpiopin.h:143
GPIOpin_t GPIOpin_init(GPIO_TypeDef *, GPIO_Pin, GPIO_Config *)
Initialiser for a GPIO peripheral pin interface.
Definition gpiopin.c:28
@ GPIO_AF9
CAN1/CAN2, LTDC, TIM12..14.
Definition gpiopin.h:82
@ GPIO_PIN11
Pin 11.
Definition gpiopin.h:61
@ GPIO_PIN12
Pin 12.
Definition gpiopin.h:62
@ GPIO_MODE_AF
Alternate function mode.
Definition gpiopin.h:98
Struct definition for GPIO configuration.
Definition gpiopin.h:138
Definition can.h:22
Definition can.h:28