Open Model Railroad Network (OpenMRN)
Loading...
Searching...
No Matches
Lpc17xx40xxCan.cxx
Go to the documentation of this file.
1
35#include <stdint.h>
36
37#include "Lpc17xx40xxCan.hxx"
38
39#include "chip.h"
40#include "nmranet_config.h"
41
42LpcCan *LpcCan::instances[2] = {NULL};
43unsigned int LpcCan::intCount = 0;
44
49LpcCan::LpcCan(const char *name, LPC_CAN_T *base)
50 : Can(name)
51 , base(base)
52{
53 if (base == LPC_CAN1)
54 {
55 instances[0] = this;
56 }
57 else if (base == LPC_CAN2)
58 {
59 instances[1] = this;
60 }
61 else
62 {
63 HASSERT(0);
64 }
65
66 /* should already be disabled, but just in case */
67 NVIC_DisableIRQ(CAN_IRQn);
68
69 /* The priority of CAN interrupt is as high as possible while maintaining
70 * FreeRTOS compatibility.
71 */
72 NVIC_SetPriority(CAN_IRQn, configKERNEL_INTERRUPT_PRIORITY);
73}
74
78{
79 Chip_CAN_Init(base, LPC_CANAF, LPC_CANAF_RAM);
80 if (base == LPC_CAN2)
81 {
82 Chip_CAN_SetBitRate(base, config_nmranet_can_bitrate());
83 }
84 else if (base == LPC_CAN1)
85 {
86 Chip_CAN_SetBitRate(base, config_can2_bitrate());
87 }
88 else
89 {
90 DIE("Unknown CAN base address.");
91 }
92 Chip_CAN_SetAFMode(LPC_CANAF, CAN_AF_BYBASS_MODE);
93 Chip_CAN_EnableInt(base, CAN_IER_BITMASK &
94 ~(CAN_IER_TIE2 | CAN_IER_TIE3 | CAN_ICR_IDI));
95
96 if (intCount++ == 0)
97 {
98 NVIC_EnableIRQ(CAN_IRQn);
99 }
100}
101
105{
106 if (--intCount == 0)
107 {
108 NVIC_DisableIRQ(CAN_IRQn);
109 }
110 Chip_CAN_DisableInt(base, CAN_IER_BITMASK &
111 ~(CAN_IER_TIE2 | CAN_IER_TIE3 | CAN_ICR_IDI));
112 Chip_CAN_DeInit(base);
113}
114
115/* Try and transmit a message.
116 */
118{
119 if (Chip_CAN_GetStatus(base) & CAN_SR_TBS(0))
120 {
121 struct can_frame *can_frame;
122
123 if (txBuf->data_read_pointer(&can_frame))
124 {
125 /* The LPC Chip drivers perform a lot of extra copying, which is
126 * stupid. We can do significantly better by using the structure
127 * members in the can_17xx_40xx.h header directly.
128 */
129
130 /* load the next message to transmit */
131 base->TX[0].TFI = 0;
132 if (can_frame->can_eff)
133 {
134 base->TX[0].TFI |= CAN_TFI_FF;
135 base->TX[0].TID = CAN_TID_ID29(can_frame->can_id);
136 }
137 else
138 {
139 base->TX[0].TID = CAN_TID_ID11(can_frame->can_id);
140 }
141 if (can_frame->can_rtr)
142 {
143 base->TX[0].TFI |= CAN_TFI_RTR;
144 }
145 else
146 {
147 base->TX[0].TFI |= CAN_TFI_DLC(can_frame->can_dlc);
148 for (unsigned i = 0; i < (CAN_MSG_MAX_DATA_LEN + 3) / 4; ++i)
149 {
150 base->TX[0].TD[i] = (can_frame->data[4 * i + 0] << 0) |
151 (can_frame->data[4 * i + 1] << 8) |
152 (can_frame->data[4 * i + 2] << 16) |
153 (can_frame->data[4 * i + 3] << 24);
154 }
155 }
156
157 Chip_CAN_SetCmd(base, CAN_CMR_STB(0) | CAN_CMR_TR);
158 txBuf->consume(1);
160 }
161 }
162}
163
167void LpcCan::interrupt_handler(uint32_t status)
168{
169 if (status & CAN_ICR_EI)
170 {
172 /* flush and data in the tx pipeline */
173 Chip_CAN_SetCmd(base, CAN_CMR_TR);
174 txBuf->flush();
176 }
177 if (status & CAN_ICR_DOI)
178 {
179 /* receive buffer overrun */
180 ++overrunCount;
181 }
182 if (status & CAN_ICR_WUI)
183 {
184 /* wakeup from activity */
185 }
186 if (status & CAN_ICR_EPI)
187 {
188 /* In error passive state */
189 }
190 if (status & CAN_ICR_ALI)
191 {
192 /* Arbitration lost */
193 }
194 if (status & CAN_ICR_BEI)
195 {
196 /* bus off error condition */
197 ++busOffCount;
198 /* flush and data in the tx pipeline */
199 Chip_CAN_SetCmd(base, CAN_CMR_TR);
200 txBuf->flush();
202 /* reset controller */
203 Chip_CAN_SetMode(base, CAN_RESET_MODE, DISABLE);
204 }
205 if (status & CAN_ICR_IDI)
206 {
207 /* transmission successful or aborted */
208 }
209 if (status & CAN_ICR_RI)
210 {
211 /* rx data received */
212 struct can_frame *can_frame;
213 if (rxBuf->data_write_pointer(&can_frame))
214 {
215 if (base->SR & CAN_SR_RBS(0))
216 {
217 can_frame->can_id = (base->RX.RFS & CAN_RFS_FF) ?
218 CAN_RID_ID_29(base->RX.RID) :
219 CAN_RID_ID_11(base->RX.RID);
220 can_frame->can_rtr = (base->RX.RFS & CAN_RFS_RTR) ? 1 : 0;
221 can_frame->can_err = 0;
222 if (base->RX.RFS & CAN_RFS_FF)
223 {
224 can_frame->can_eff = 1;
225 can_frame->can_id = CAN_RID_ID_29(base->RX.RID);
226 }
227 else
228 {
229 can_frame->can_eff = 0;
230 can_frame->can_id = CAN_RID_ID_11(base->RX.RID);
231 }
232 can_frame->can_dlc = CAN_RFS_DLC(base->RX.RFS);
233 if (base->RX.RFS & CAN_RFS_RTR)
234 {
235 can_frame->can_rtr = 1;
236 }
237 else
238 {
239 can_frame->can_rtr = 0;
240 can_frame->data[0] = (base->RX.RD[0] >> 0) & 0xFF;
241 can_frame->data[1] = (base->RX.RD[0] >> 8) & 0xFF;
242 can_frame->data[2] = (base->RX.RD[0] >> 16) & 0xFF;
243 can_frame->data[3] = (base->RX.RD[0] >> 24) & 0xFF;
244 can_frame->data[4] = (base->RX.RD[1] >> 0) & 0xFF;
245 can_frame->data[5] = (base->RX.RD[1] >> 8) & 0xFF;
246 can_frame->data[6] = (base->RX.RD[1] >> 16) & 0xFF;
247 can_frame->data[7] = (base->RX.RD[1] >> 24) & 0xFF;
248 }
249 Chip_CAN_SetCmd(base, CAN_CMR_RRB);
250 rxBuf->advance(1);
252
256 if (readableNotify_)
257 {
258 readableNotify_->notify_from_isr();
259 readableNotify_ = nullptr;
260 }
261 }
262 }
263 else
264 {
265 /* ran out of space to buffer, flush incoming message */
266 ++overrunCount;
267 Chip_CAN_SetCmd(base, CAN_CMR_RRB);
268 }
269 }
270 if (status & CAN_ICR_TI1)
271 {
272 struct can_frame *can_frame;
273
274 if (txBuf->data_read_pointer(&can_frame))
275 {
276 /* The LPC Chip drivers perform a lot of extra copying, which is
277 * stupid. We can do significantly better by using the structure
278 * members in the can_17xx_40xx.h header directly.
279 */
280
281 /* load the next message to transmit */
282 base->TX[0].TFI = 0;
283 if (can_frame->can_eff)
284 {
285 base->TX[0].TFI |= CAN_TFI_FF;
286 base->TX[0].TID = CAN_TID_ID29(can_frame->can_id);
287 }
288 else
289 {
290 base->TX[0].TID = CAN_TID_ID11(can_frame->can_id);
291 }
292 if (can_frame->can_rtr)
293 {
294 base->TX[0].TFI |= CAN_TFI_RTR;
295 }
296 else
297 {
298 base->TX[0].TFI |= CAN_TFI_DLC(can_frame->can_dlc);
299 for (unsigned i = 0; i < (CAN_MSG_MAX_DATA_LEN + 3) / 4; ++i)
300 {
301 base->TX[0].TD[i] = (can_frame->data[4 * i + 0] << 0) |
302 (can_frame->data[4 * i + 1] << 8) |
303 (can_frame->data[4 * i + 2] << 16) |
304 (can_frame->data[4 * i + 3] << 24);
305 }
306 }
307
308 Chip_CAN_SetCmd(base, CAN_CMR_STB(0) | CAN_CMR_TR);
309 txBuf->consume(1);
311
315 if (writableNotify_)
316 {
317 writableNotify_->notify_from_isr();
318 writableNotify_= nullptr;
319 }
320 }
321 }
322}
323
324extern "C" {
331
332} // extern "C"
void can_interrupt_handler(void)
This is the interrupt handler for the can device(s).
Base class for a CAN device for the Arduino environment.
unsigned int overrunCount
overrun count
unsigned int softErrorCount
soft error count
DeviceBuffer< struct can_frame > * txBuf
transmit buffer
unsigned int busOffCount
bus-off count
DeviceBuffer< struct can_frame > * rxBuf
receive buffer
void flush()
flush all the data out of the buffer and reset the buffer.
size_t advance(size_t items)
Add a number of items to the buffer by advancing the writeIndex.
void signal_condition()
Signal the wakeup condition.
size_t consume(size_t items)
Remove a number of items from the buffer by advancing the readIndex.
void signal_condition_from_isr()
Signal the wakeup condition from an ISR context.
size_t data_write_pointer(T **buf)
Get a reference to the current location in the buffer for write.
size_t data_read_pointer(T **buf)
Get a reference to the current location in the buffer for read.
Specialization of CAN driver for LPC17xx and LPC40xx CAN.
void enable() override
function to enable device
void disable() override
function to disable device
static unsigned int intCount
one interrupt vector is shared between two CAN controllers, so we need to keep track of the number of...
static void interrupt_handler()
Translate an interrupt handler into C++ object context.
void tx_msg() override
function to try and transmit a message
static LpcCan * instances[2]
Instance pointers help us get context from the interrupt handler(s)
LPC_CAN_T * base
base address of this device
LpcCan()
Default constructor.
Notifiable * readableNotify_
This will be notified if the device has data avilable for read.
Definition Devtab.hxx:635
Notifiable * writableNotify_
This will be notified if the device has buffer avilable for write.
Definition Devtab.hxx:637
#define HASSERT(x)
Checks that the value of expression x is true, else terminates the current process.
Definition macros.h:138
#define DIE(MSG)
Unconditionally terminates the current process with a message.
Definition macros.h:143