Open Model Railroad Network (OpenMRN)
Loading...
Searching...
No Matches
mbed_can.cpp
Go to the documentation of this file.
1
35#include "mbed.h"
36#include "Can.hxx"
37#ifdef TARGET_LPC2368
38#include "lpc23xx.h"
39
40int tx_led = 0;
41
42#endif
43
44#ifdef TARGET_LPC1768
45#include "LPC17xx.h"
46
47extern DigitalOut d1;
48DigitalOut& tx_led = d1;
49
50#endif
51
59class MbedCanDriver : public Can
60{
61public:
63 enum Instance {
64 CAN1,
65 CAN2
66 };
72 MbedCanDriver(Instance instance, const char *dev, int frequency)
73 : Can(dev)
74 , mbedCan_(
75 instance == CAN1 ? P0_0 : P0_4, instance == CAN1 ? P0_1 : P0_5)
76 , SR_(instance == CAN1 ? &LPC_CAN1->SR : &LPC_CAN2->SR)
77 {
78 mbedCan_.frequency(frequency);
80 }
81private:
82 void enable() override {};
83 void disable() override {};
84 void flush_buffers() override {};
86 void interrupt();
87 void tx_msg() OVERRIDE;
88
90 mbed::CAN mbedCan_;
92 volatile uint32_t* SR_;
96};
97
102{
103 if (txPending_)
104 return;
105 if (!(*SR_ & 0x4))
106 return; // TX buffer is holding a packet
107
108 struct can_frame *can_frame;
112 taskENTER_CRITICAL();
113 if (!txBuf->data_read_pointer(&can_frame))
114 {
115 taskEXIT_CRITICAL();
116 return;
117 }
118 CANMessage msg(can_frame->can_id, (const char*)can_frame->data,
119 can_frame->can_dlc, can_frame->can_rtr ? CANRemote : CANData,
120 can_frame->can_eff ? CANExtended : CANStandard);
121 if (!mbedCan_.write(msg))
122 {
123 // NOTE(balazs.racz): This means that the CAN layer didn't find an
124 // available TX buffer to send the CAN message. However, since
125 // txPending == 0 at this point, that can only happen if someone else
126 // was also writing frames to this CAN device. We won't handle that
127 // case now.
128 overrunCount++;
129 }
130 else
131 {
132 txBuf->consume(1);
134 }
135 txPending_ = 1;
136 tx_led = 1;
137 taskEXIT_CRITICAL();
138}
139
142{
143 int woken = 0;
144 CANMessage msg;
145 if (mbedCan_.read(msg))
146 {
147 struct can_frame* can_frame;
148 if (rxBuf->data_write_pointer(&can_frame))
149 {
150 can_frame->can_id = msg.id;
151 can_frame->can_rtr = msg.type == CANRemote ? 1 : 0;
152 can_frame->can_eff = msg.format == CANStandard ? 0 : 1;
153 can_frame->can_err = 0;
154 can_frame->can_dlc = msg.len;
155 memcpy(can_frame->data, msg.data, msg.len);
156 rxBuf->advance(1);
158 }
159 else
160 {
161 ++overrunCount;
162 }
163 }
164#if defined(TARGET_LPC2368) || defined(TARGET_LPC1768)
165 if (*SR_ & 0x4)
166 {
167 // Transmit buffer 1 empty => transmit finished.
168 struct can_frame *can_frame;
169 if (txBuf->data_read_pointer(&can_frame))
170 {
171 CANMessage msg(can_frame->can_id, (const char*)can_frame->data,
172 can_frame->can_dlc,
173 can_frame->can_rtr ? CANRemote : CANData,
174 can_frame->can_eff ? CANExtended : CANStandard);
175 if (mbedCan_.write(msg))
176 {
177 tx_led = 1;
178 txPending_ = 1;
179 txBuf->consume(1);
181 }
182 else
183 {
184 // NOTE(balazs.racz): This is an inconsistency -- if *SR&0x4
185 // then TX1 buffer is empty, so if write fails, then... a task
186 // switch occured while serving an interrupt handler?
187 overrunCount++;
188 tx_led = 0;
189 txPending_ = 0;
190 }
191 }
192 else
193 {
194 tx_led = 0;
195 txPending_ = 0;
196 }
197 }
198#else
199#error you need to define how to figure out whether the transmit buffer is empty.
200#endif
203 if (woken)
204 {
205#ifdef TARGET_LPC1768
206 portYIELD();
207#elif defined(TARGET_LPC2368)
211#else
212#error define how to yield on your CPU.
213#endif
214 }
215}
216
218MbedCanDriver can0(MbedCanDriver::CAN2, "/dev/can0", config_nmranet_can_bitrate());
220MbedCanDriver can1(MbedCanDriver::CAN1, "/dev/can1", config_can2_bitrate() ? config_can2_bitrate() : config_nmranet_can_bitrate());
Base class for a CAN device for the Arduino environment.
unsigned int overrunCount
overrun count
DeviceBuffer< struct can_frame > * txBuf
transmit buffer
DeviceBuffer< struct can_frame > * rxBuf
receive 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.
CAN driver implementation using an mbed-supported CAN device.
Definition mbed_can.cpp:60
void interrupt()
called after disabling the dev
Definition mbed_can.cpp:141
Instance
Which hardware device to use.
Definition mbed_can.cpp:63
void enable() override
function to enable device
Definition mbed_can.cpp:82
MbedCanDriver(Instance instance, const char *dev, int frequency)
Constructor.
Definition mbed_can.cpp:72
volatile uint32_t * SR_
Status register.
Definition mbed_can.cpp:92
void flush_buffers() override
function to disable device
Definition mbed_can.cpp:84
void tx_msg() OVERRIDE
Try and transmit a message.
Definition mbed_can.cpp:101
void disable() override
function to enable device
Definition mbed_can.cpp:83
char txPending_
Whether we have an output frame pending (1) or the output frame is free (0).
Definition mbed_can.cpp:95
mbed::CAN mbedCan_
mBed CAN implementation object.
Definition mbed_can.cpp:90
#define OVERRIDE
Function attribute for virtual functions declaring that this funciton is overriding a funciton that s...
Definition macros.h:180
MbedCanDriver can1(MbedCanDriver::CAN1, "/dev/can1", config_can2_bitrate() ? config_can2_bitrate() :config_nmranet_can_bitrate())
Other CAN driver instance.
MbedCanDriver can0(MbedCanDriver::CAN2, "/dev/can0", config_nmranet_can_bitrate())
The TCH baseboard for the mbed has CAN1 and CAN2 mixed up.