16
16
#ifndef MODM_MCP2515_HPP
17
17
#error "Don't include this file directly, use 'mcp2515.hpp' instead!"
18
18
#endif
19
-
20
19
#include " mcp2515_bit_timings.hpp"
21
20
#include " mcp2515_definitions.hpp"
21
+ #include < modm/architecture/driver/atomic/queue.hpp>
22
22
#include < modm/architecture/interface/assert.hpp>
23
-
23
+ #include < modm/architecture/interface/interrupt.hpp>
24
+ #include < modm/platform/exti/exti.hpp>
24
25
25
26
#undef MODM_LOG_LEVEL
26
27
#define MODM_LOG_LEVEL modm::log::DISABLED
27
28
29
+ static modm::atomic::Queue<modm::can::Message, 32 > txQueue;
30
+ static modm::atomic::Queue<modm::can::Message, 32 > rxQueue;
31
+
28
32
// ----------------------------------------------------------------------------
29
33
template <typename SPI, typename CS, typename INT>
30
34
SPI modm::Mcp2515<SPI, CS, INT>::spi;
@@ -119,6 +123,12 @@ modm::Mcp2515<SPI, CS, INT>::initialize()
119
123
{
120
124
using Timings = modm::CanBitTimingMcp2515<externalClockFrequency, bitrate>;
121
125
126
+ // initialize interrrupt on INT pin
127
+
128
+ modm::platform::Exti::connect<INT>(modm::platform::Exti::Trigger::FallingEdge, [](uint8_t ){
129
+ mcp2515interrupt ();
130
+ });
131
+
122
132
return initializeWithPrescaler (
123
133
Timings::getPrescaler (),
124
134
Timings::getSJW (),
@@ -186,22 +196,73 @@ modm::Mcp2515<SPI, CS, INT>::setMode(Can::Mode mode)
186
196
}
187
197
188
198
// ----------------------------------------------------------------------------
199
+
189
200
template <typename SPI, typename CS, typename INT>
190
201
bool
191
202
modm::Mcp2515<SPI, CS, INT>::isMessageAvailable()
192
203
{
193
- return !interruptPin.read ();
204
+ return rxQueue.isNotEmpty ();
205
+ }
206
+
207
+ template <typename SPI, typename CS, typename INT>
208
+ bool
209
+ modm::Mcp2515<SPI, CS, INT>::getMessage(can::Message& message, uint8_t * /* filter_id*/ )
210
+ {
211
+ if (rxQueue.isEmpty ())
212
+ {
213
+ // no message in the receive buffer
214
+ return false ;
215
+ }
216
+ else {
217
+ auto & rxMessage = rxQueue.get ();
218
+ memcpy (&message, &rxMessage, sizeof (message));
219
+ rxQueue.pop ();
220
+ return true ;
221
+ }
194
222
}
195
223
196
224
// ----------------------------------------------------------------------------
197
225
template <typename SPI, typename CS, typename INT>
198
226
bool
199
- modm::Mcp2515<SPI, CS, INT>::getMessage(can::Message& message )
227
+ modm::Mcp2515<SPI, CS, INT>::isReadyToSend( )
200
228
{
229
+ return txQueue.isNotFull ();
230
+ }
231
+
232
+ // ----------------------------------------------------------------------------
233
+ template <typename SPI, typename CS, typename INT>
234
+ bool
235
+ modm::Mcp2515<SPI, CS, INT>::sendMessage(const can::Message& message)
236
+ {
237
+ if (not modm_assert_continue_ignore (txQueue.push (message), " mcp2515.can.tx" ,
238
+ " CAN transmit software buffer overflowed!" , 1 )) {
239
+ return false ;
240
+ }
241
+ return true ;
242
+ }
243
+
244
+ // ----------------------------------------------------------------------------
245
+ template <typename SPI, typename CS, typename INT>
246
+ void
247
+ modm::Mcp2515<SPI, CS, INT>::mcp2515interrupt(){
248
+ using namespace mcp2515 ;
249
+
250
+ can::Message message;
251
+ bool success = mcp2515readMessage (message);
252
+ if (success){
253
+ modm_assert_continue_ignore (rxQueue.push (message), " mcp2515.can.rx.sw0" ,
254
+ " CAN receive software buffer overflowed!" , 1 );
255
+ }
256
+ }
257
+
258
+ template <typename SPI, typename CS, typename INT>
259
+ bool
260
+ modm::Mcp2515<SPI, CS, INT>::mcp2515readMessage(can::Message& message){
201
261
using namespace mcp2515 ;
202
262
203
263
uint8_t status = readStatus (RX_STATUS);
204
264
uint8_t address;
265
+
205
266
if (status & FLAG_RXB0_FULL) {
206
267
address = READ_RX; // message in buffer 0
207
268
}
@@ -231,15 +292,33 @@ modm::Mcp2515<SPI, CS, INT>::getMessage(can::Message& message)
231
292
232
293
// RX0IF or RX1IF respectivly were already cleared automatically by rising CS.
233
294
// See section 12.4 in datasheet.
234
-
235
295
return true ;
236
296
}
237
297
298
+ template <typename SPI, typename CS, typename INT>
299
+ bool
300
+ modm::Mcp2515<SPI, CS, INT>::update(){
301
+ // / todo
302
+ // / this should be a timer interrupt
303
+ using namespace mcp2515 ;
304
+
305
+ bool hasSend = false ;
306
+ // / check if device accepts messages and start emptying the transmit queue if not empty
307
+ if (txQueue.isNotEmpty ())
308
+ {
309
+ if (mcp2515isReadyToSend ()){
310
+ hasSend = mcp2515sendMessage (txQueue.get ());
311
+ txQueue.pop ();
312
+ }
313
+ }
314
+ return hasSend;
315
+ }
316
+
238
317
// ----------------------------------------------------------------------------
239
318
240
319
template <typename SPI, typename CS, typename INT>
241
320
bool
242
- modm::Mcp2515<SPI, CS, INT>::isReadyToSend ()
321
+ modm::Mcp2515<SPI, CS, INT>::mcp2515isReadyToSend ()
243
322
{
244
323
using namespace mcp2515 ;
245
324
@@ -258,7 +337,7 @@ modm::Mcp2515<SPI, CS, INT>::isReadyToSend()
258
337
259
338
template <typename SPI, typename CS, typename INT>
260
339
bool
261
- modm::Mcp2515<SPI, CS, INT>::sendMessage (const can::Message& message)
340
+ modm::Mcp2515<SPI, CS, INT>::mcp2515sendMessage (const can::Message& message)
262
341
{
263
342
using namespace mcp2515 ;
264
343
@@ -303,7 +382,7 @@ modm::Mcp2515<SPI, CS, INT>::sendMessage(const can::Message& message)
303
382
spi.transferBlocking (RTS | address);
304
383
chipSelect.set ();
305
384
306
- return address;
385
+ return static_cast < bool >( address) ;
307
386
}
308
387
309
388
// ----------------------------------------------------------------------------
0 commit comments