Dual Can PICO V1.0
Raspberry PICO is an interesting extension of Raspberry family. It is based on RP2040 microcontroller, a dual-core Arm Cortex-M0+ processor, flexible clock running up to 133 MHz 264kB on-chip SRAM 2MB on-board QSPI flash, 26 GPIO pins, including 3 analogue inputs.
There are the following peripherals:
- 2 × UART
- 2 × SPI controllers
- 2 × I2C controllers
- 16 × PWM channels
- 1 × USB 1.1 controller and PHY, with host and device support
- 8 × PIO state machines

Dual Can Bus PICO is an adapter to use our Can Bus Board with PICO. The idea is to connect all the 40 pins connector of Raspberry to the new board.




Buy on our shop
Hardware Files
All our projects are open hardware, these are the production files:
Software Configuration
An embedded system is very interesting for open hardware community only if it is well supported with free IDE and library. There are two IDE software to develop firmware: Arduino IDE and Visual Studio Code.
For stability and simplicity we prefer to use Arduino IDE. The RP2040 core used in this example is developed by Earle Philhower. Use the following steps to prepare the IDE:
- Open IDE
- Click on File
- Click on Preference

- Click on Additional Board Manager URLs and add this link https://github.com/earlephilhower/arduino-pico/releases/download/global/package_rp2040_index.json

- Click OK
- Click on Tools
- Click on Board Manager
- Install RP2040 core

- Install ACAN2515 of Pierre Molinaro
- Click on Sketch
- Include Library
- Manage Libraries

- Select Raspberry Pi PICO
Dual Can Bus Sketch
Download PicoDualCan_V1.0.ino
There are two kind of RTC for our boards, the DS3231 and PCF85063. Verify the installed RTC on your board and enabled the correct #define.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 |
//—————————————————————————————————————————————————————————————————————————————— // SG Electronic Systems srls // This Example is derived by // ACAN2515 Demo in loopback mode, for the Raspberry Pi Pico // Thanks to Duncan Greenwood for providing this sample sketch //—————————————————————————————————————————————————————————————————————————————— // Pico Adapter Pinout // SPI0_SCK 2 // SPI0_MISO 0 // SPI0_MOSI 3 // SPI0_CS0 1 CAN0 // SPI0_CS1 9 CAN1 // MCP2515_INT1 4 CAN0 // MCP2515_INT2 12 CAN1 // SPI1_SCK 10 // SPI1_MISO 8 // SPI1_MOSI 11 // SPI1_CS0 6 // SPI1_CS1 13 // I2C0_SDA 20 RTC // I2C0_SCL 21 RTC // I2C1_SDA 14 // I2C1_SCL 15 // LED1 18 // LED2 19 // UART0_RX 17 // UART0_TX 16 #ifndef ARDUINO_ARCH_RP2040 #error "Select a Raspberry Pi Pico board" #endif #define LED1 18 #define LED2 19 #define LED #define CAN0 #define CAN1 #define RTC #define RTC_DS3231 //#define RTC_PCF85063 //—————————————————————————————————————————————————————————————————————————————— #include <Wire.h> #ifdef RTC_DS3231 #include "DS3231.h" #endif #ifdef RTC_PCF85063 #include "PCF85063TP.h" #endif #include <ACAN2515.h> //—————————————————————————————————————————————————————————————————————————————— // The Pico has two SPI peripherals, SPI and SPI1. Either (or both) can be used. // The are no default pin assignments so they must be set explicitly. // Testing was done with Earle Philhower's arduino-pico core: // https://github.com/earlephilhower/arduino-pico //—————————————————————————————————————————————————————————————————————————————— static const byte SPI0_SCK = 2 ; // SCK input of MCP2515 static const byte SPI0_MOSI = 3 ; // SDI input of MCP2515 static const byte SPI0_MISO = 0 ; // SDO output of MCP2515 static const byte SPI0_CS0 = 1 ; // CS input of MCP2515 1 static const byte SPI0_CS1 = 9 ; // CS input of MCP2515 (2 static const byte I2C0_SDA = 20 ; static const byte I2C0_SCL = 21 ; #ifdef CAN0 static const byte MCP2515_INT0 = 4 ; // INT output of MCP2515 (adapt to your design) ACAN2515 can0 (SPI0_CS0, SPI, MCP2515_INT0) ; #endif #ifdef CAN1 static const byte MCP2515_INT1 = 12 ; // INT output of MCP2515 (adapt to your design) ACAN2515 can1 (SPI0_CS1, SPI, MCP2515_INT1) ; #endif #ifdef RTC_DS3231 #define DS3231_I2C_ADDRESS 0x68 #endif #ifdef RTC_PCF85063 PCD85063TP clock;//define a object of PCD85063TP class #endif static const uint32_t QUARTZ_FREQUENCY = 16UL * 1000UL * 1000UL ; // 16 MHz static uint32_t gBlinkLedDate0 = 0 ; static uint32_t gReceivedFrameCount0 = 0 ; static uint32_t gSentFrameCount0 = 0 ; static uint32_t gBlinkLedDate1 = 0 ; static uint32_t gReceivedFrameCount1 = 0 ; static uint32_t gSentFrameCount1 = 0 ; //—————————————————————————————————————————————————————————————————————————————— // SETUP //—————————————————————————————————————————————————————————————————————————————— void setup () { #ifdef LED pinMode (LED1, OUTPUT) ; // For CAN0 digitalWrite (LED1, HIGH) ; pinMode (LED2, OUTPUT) ; // For CAN1 digitalWrite (LED2, HIGH) ; #else //--- Switch on builtin led pinMode (LED_BUILTIN, OUTPUT) ; digitalWrite (LED_BUILTIN, HIGH) ; #endif //--- Start serial Serial.begin (115200) ; //--- Wait for serial (blink led at 10 Hz during waiting) while (!Serial) { delay (50) ; #ifdef LED digitalWrite (LED1, !digitalRead (LED1)) ; delay (50) ; digitalWrite (LED2, !digitalRead (LED2)) ; #else digitalWrite (LED_BUILTIN, !digitalRead (LED_BUILTIN)) ; #endif } //--- There are no default SPI pins so they must be explicitly assigned SPI.setSCK(SPI0_SCK); SPI.setTX(SPI0_MOSI); SPI.setRX(SPI0_MISO); //--- Begin SPI SPI.begin () ; #ifdef CAN0 //--- Configure ACAN2515 Serial.println ("Configure ACAN2515 CAN0") ; ACAN2515Settings settings0 (QUARTZ_FREQUENCY, 125UL * 1000UL) ; // CAN bit rate 125 kb/s settings0.mRequestedMode = ACAN2515Settings::NormalMode ; // Select NormalMode mode const uint16_t errorCode0 = can0.begin (settings0, [] { can0.isr () ; }) ; if (errorCode0 == 0) { Serial.print ("Bit Rate prescaler: ") ; Serial.println (settings0.mBitRatePrescaler) ; Serial.print ("Propagation Segment: ") ; Serial.println (settings0.mPropagationSegment) ; Serial.print ("Phase segment 1: ") ; Serial.println (settings0.mPhaseSegment1) ; Serial.print ("Phase segment 2: ") ; Serial.println (settings0.mPhaseSegment2) ; Serial.print ("SJW: ") ; Serial.println (settings0.mSJW) ; Serial.print ("Triple Sampling: ") ; Serial.println (settings0.mTripleSampling ? "yes" : "no") ; Serial.print ("Actual bit rate: ") ; Serial.print (settings0.actualBitRate ()) ; Serial.println (" bit/s") ; Serial.print ("Exact bit rate ? ") ; Serial.println (settings0.exactBitRate () ? "yes" : "no") ; Serial.print ("Sample point: ") ; Serial.print (settings0.samplePointFromBitStart ()) ; Serial.println ("%") ; } else { Serial.print ("Configuration 0 error 0x") ; Serial.println (errorCode0, HEX) ; } #endif #ifdef CAN1 //--- There are no default SPI pins so they must be explicitly assigned //--- Configure ACAN2515 CAN1 Serial.println ("Configure ACAN2515 CAN1") ; ACAN2515Settings settings1 (QUARTZ_FREQUENCY, 125UL * 1000UL) ; // can1 bit rate 125 kb/s settings1.mRequestedMode = ACAN2515Settings::NormalMode ; // Select NormalMode mode const uint16_t errorCode1 = can1.begin (settings1, [] { can1.isr () ; }) ; if (errorCode1 == 0) { Serial.print ("Bit Rate prescaler: ") ; Serial.println (settings1.mBitRatePrescaler) ; Serial.print ("Propagation Segment: ") ; Serial.println (settings1.mPropagationSegment) ; Serial.print ("Phase segment 1: ") ; Serial.println (settings1.mPhaseSegment1) ; Serial.print ("Phase segment 2: ") ; Serial.println (settings1.mPhaseSegment2) ; Serial.print ("SJW: ") ; Serial.println (settings1.mSJW) ; Serial.print ("Triple Sampling: ") ; Serial.println (settings1.mTripleSampling ? "yes" : "no") ; Serial.print ("Actual bit rate: ") ; Serial.print (settings1.actualBitRate ()) ; Serial.println (" bit/s") ; Serial.print ("Exact bit rate ? ") ; Serial.println (settings1.exactBitRate () ? "yes" : "no") ; Serial.print ("Sample point: ") ; Serial.print (settings1.samplePointFromBitStart ()) ; Serial.println ("%") ; }else{ Serial.print ("Configuration 1 error 0x") ; Serial.println (errorCode1, HEX) ; } #endif #ifdef RTC Wire.setSDA(I2C0_SDA); Wire.setSCL(I2C0_SCL); Wire.begin(); #endif #ifdef RTC_PCF85063 clock.begin(); //clock.setcalibration(1, 32767.2); // Setting offset by clock frequency uint8_t ret = clock.calibratBySeconds(0, -0.000041); Serial.print("offset value: "); Serial.print("0x"); Serial.println(ret, HEX); #endif } #ifdef RTC_PCF85063 void displayTime() { char minute, hour, dayOfWeek, dayOfMonth, month, year, second; clock.getTime(); second = clock.second; minute = clock.minute; hour = clock.hour; dayOfWeek = clock.dayOfWeek; dayOfMonth = clock.dayOfMonth; month = clock.month; year = clock.year+2000; // send it to the serial monitor Serial.print(hour, DEC); // convert the byte variable to a decimal number when displayed Serial.print(":"); if (minute<10) { Serial.print("0"); } Serial.print(minute, DEC); Serial.print(":"); if (second<10) { Serial.print("0"); } Serial.print(second, DEC); Serial.print(" "); Serial.print(dayOfMonth, DEC); Serial.print("/"); Serial.print(month, DEC); Serial.print("/"); Serial.print(year, DEC); Serial.print(" Day of week: "); switch(dayOfWeek){ case 1:{ Serial.println("Sunday"); } break; case 2:{ Serial.println("Monday"); } break; case 3:{ Serial.println("Tuesday"); } break; case 4:{ Serial.println("Wednesday"); } break; case 5:{ Serial.println("Thursday"); } break; case 6:{ Serial.println("Friday"); } break; case 7:{ Serial.println("Saturday"); } break; default: Serial.println(); break; } } #endif #ifdef RTC_DS3231 // Convert normal decimal numbers to binary coded decimal byte decToBcd(byte val) { return( (val/10*16) + (val%10) ); } // Convert binary coded decimal to normal decimal numbers byte bcdToDec(byte val) { return( (val/16*10) + (val%16) ); } void setDS3231time(byte second, byte minute, byte hour, byte dayOfWeek, byte dayOfMonth, byte month, byte year) { // sets time and date data to DS3231 Wire.beginTransmission(DS3231_I2C_ADDRESS); Wire.write(0); // set next input to start at the seconds register Wire.write(decToBcd(second)); // set seconds Wire.write(decToBcd(minute)); // set minutes Wire.write(decToBcd(hour)); // set hours Wire.write(decToBcd(dayOfWeek)); // set day of week (1=Sunday, 7=Saturday) Wire.write(decToBcd(dayOfMonth)); // set date (1 to 31) Wire.write(decToBcd(month)); // set month Wire.write(decToBcd(year)); // set year (0 to 99) Wire.endTransmission(); } void readDS3231time(byte *second, byte *minute, byte *hour, byte *dayOfWeek, byte *dayOfMonth, byte *month, byte *year) { Wire.beginTransmission(DS3231_I2C_ADDRESS); Wire.write(0); // set DS3231 register pointer to 00h Wire.endTransmission(); Wire.requestFrom(DS3231_I2C_ADDRESS, 7); // request seven bytes of data from DS3231 starting from register 00h *second = bcdToDec(Wire.read() & 0x7f); *minute = bcdToDec(Wire.read()); *hour = bcdToDec(Wire.read() & 0x3f); *dayOfWeek = bcdToDec(Wire.read()); *dayOfMonth = bcdToDec(Wire.read()); *month = bcdToDec(Wire.read()); *year = bcdToDec(Wire.read()); } void displayTime() { byte minute, hour, dayOfWeek, dayOfMonth, month, year, second; // retrieve data from DS3231 readDS3231time(&second, &minute, &hour, &dayOfWeek, &dayOfMonth, &month, &year); // send it to the serial monitor Serial.print(hour, DEC); // convert the byte variable to a decimal number when displayed Serial.print(":"); if (minute<10) { Serial.print("0"); } Serial.print(minute, DEC); Serial.print(":"); if (second<10) { Serial.print("0"); } Serial.print(second, DEC); Serial.print(" "); Serial.print(dayOfMonth, DEC); Serial.print("/"); Serial.print(month, DEC); Serial.print("/"); Serial.print(year, DEC); Serial.print(" Day of week: "); switch(dayOfWeek){ case 1:{ Serial.println("Sunday"); } break; case 2:{ Serial.println("Monday"); } break; case 3:{ Serial.println("Tuesday"); } break; case 4:{ Serial.println("Wednesday"); } break; case 5:{ Serial.println("Thursday"); } break; case 6:{ Serial.println("Friday"); } break; case 7:{ Serial.println("Saturday"); } break; } } #endif void loop () { CANMessage frame0 ; CANMessage frame1 ; CANMessage frame_read ; can0.poll () ; can1.poll () ; frame0.id = 0x010 ; frame0.len = 8 ; frame0.data[0] = 10; frame0.data[1] = 2; frame0.data[2] = 3; frame0.data[3] = 4; frame0.data[4] = 5; frame0.data[5] = 6; frame0.data[6] = 7; frame0.data[7] = 8; frame1.id = 0x002 ; frame1.len = 8 ; frame1.data[0] = 11; frame1.data[1] = 12; frame1.data[2] = 13; frame1.data[3] = 14; frame1.data[4] = 15; frame1.data[5] = 16; frame1.data[6] = 17; frame1.data[7] = 18; int len = 0; #ifdef CAN0 // CAN0 loop if (gBlinkLedDate0 < millis ()) { gBlinkLedDate0 += 2000 ; digitalWrite (LED1, !digitalRead (LED1)) ; const bool ok0 = can0.tryToSend (frame0) ; if (ok0) { gSentFrameCount0 += 1 ; Serial.print ("Sent 0: ") ; Serial.println (gSentFrameCount0) ; } else { Serial.println ("Send failure 0") ; } } if (can0.available ()) { can0.receive (frame_read) ; gReceivedFrameCount0 ++ ; Serial.print ("CAN0 Received : ") ; Serial.print (gReceivedFrameCount0) ; Serial.print (" Id: ") ; len = frame_read.len; Serial.print (frame_read.id) ; Serial.print (" Len: ") ; Serial.print (len) ; Serial.print (" Data: ") ; for(int i = 0; i<len; i++) // print the data { Serial.print(frame_read.data[i]); Serial.print(" "); } Serial.println(); } #endif #ifdef CAN1 // CAN1 loop if (gBlinkLedDate1 < millis ()) { gBlinkLedDate1 += 1000 ; digitalWrite (LED2, !digitalRead (LED2)) ; const bool ok1 = can1.tryToSend (frame1) ; if (ok1) { gSentFrameCount1 += 1 ; Serial.print ("Sent 1: ") ; Serial.println (gSentFrameCount1) ; } else { Serial.println ("Send failure 1") ; } } if (can1.available ()) { can1.receive (frame_read) ; gReceivedFrameCount1 ++ ; Serial.print ("CAN 1 Received: ") ; Serial.print (gReceivedFrameCount1) ; Serial.print (" Id: ") ; len = frame_read.len; Serial.print (frame_read.id) ; Serial.print (" Len: ") ; Serial.print (len) ; Serial.print (" Data: ") ; for(int i = 0; i<len; i++) // print the data { Serial.print(frame_read.data[i]); Serial.print(" "); } Serial.println(); } #endif #ifdef RTC delay(500); displayTime(); #endif } //—————————————————————————————————————————————————————————————————————————————— |
Leave a Reply