├── README.md └── canbus_example ├── schematic ├── CAN_transceiver_schematic.odg └── CAN_transceiver_schematic.png ├── canbus_receiver_polling.py ├── canbus_sender.py ├── canbus_baudrate.py ├── canbus_receiver_interrupt.py └── README.md /README.md: -------------------------------------------------------------------------------- 1 | # micropython 2 | This repositoriy documents experiments with micropython and the CAN-bus. 3 | - [This](./canbus_example) is a CAN-bus example. 4 | -------------------------------------------------------------------------------- /canbus_example/schematic/CAN_transceiver_schematic.odg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hmaerki/experiment_micropython/HEAD/canbus_example/schematic/CAN_transceiver_schematic.odg -------------------------------------------------------------------------------- /canbus_example/schematic/CAN_transceiver_schematic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hmaerki/experiment_micropython/HEAD/canbus_example/schematic/CAN_transceiver_schematic.png -------------------------------------------------------------------------------- /canbus_example/canbus_receiver_polling.py: -------------------------------------------------------------------------------- 1 | # https://github.com/hmaerki/micropython/tree/master/canbus_example 2 | 3 | from pyb import CAN 4 | from pyb import LED 5 | 6 | ledBlue = LED(1) 7 | 8 | IDs = (122, 123, 124, 125) 9 | 10 | # 50kBaud 11 | can = CAN(1, CAN.NORMAL, extframe=False, prescaler=40, sjw=1, bs1=14, bs2=6) 12 | can.setfilter(0, CAN.LIST16, 0, IDs) 13 | can.restart() 14 | 15 | print("Now listening on these CAN-id's: ", IDs) 16 | 17 | while True: 18 | (id, isRTR, filterMatchIndex, telegram) = can.recv(0, timeout=100000) 19 | print("received:", telegram) 20 | if telegram == b'on': 21 | ledBlue.on() 22 | else: 23 | ledBlue.off() 24 | 25 | -------------------------------------------------------------------------------- /canbus_example/canbus_sender.py: -------------------------------------------------------------------------------- 1 | # https://github.com/hmaerki/micropython/tree/master/canbus_example 2 | 3 | from pyb import CAN 4 | from pyb import LED 5 | import pyb 6 | import micropython 7 | 8 | DESTINATION_CAN_ID = 123 9 | 10 | ledBlue = LED(1) 11 | 12 | switch = pyb.Switch() 13 | 14 | # 50kBaud 15 | can = CAN(1, CAN.NORMAL, extframe=False, prescaler=40, sjw=1, bs1=14, bs2=6) 16 | 17 | 18 | print("Press Switch to send CAN-telegrams, press to abort.") 19 | 20 | lastValue = None 21 | 22 | while True: 23 | newValue = switch.value() 24 | if lastValue != newValue: 25 | lastValue = newValue 26 | if newValue: 27 | ledBlue.on() 28 | telegram = b'on' 29 | else: 30 | ledBlue.off() 31 | telegram = b'off' 32 | 33 | print("Sending %s to CAN-id %d" % (telegram, DESTINATION_CAN_ID)) 34 | can.send(telegram, DESTINATION_CAN_ID) 35 | -------------------------------------------------------------------------------- /canbus_example/canbus_baudrate.py: -------------------------------------------------------------------------------- 1 | # https://github.com/hmaerki/micropython/tree/master/canbus_example 2 | import uos 3 | print('This is a %s v%s. %s.' % (uos.uname().sysname, uos.uname().release, uos.uname().machine)) 4 | 5 | import pyb 6 | 7 | # Get clock frequency: 8 | # https://docs.micropython.org/en/latest/pyboard/library/pyb.html#pyb.freq 9 | freq = pyb.freq() 10 | pclk1 = freq[3] # [s-1]. For the Pyboard v3: 48'000'000 (48MHz) 11 | 12 | # Don't know if these values are correct for all baudrates. 13 | # However, there sum must be 20! 14 | BS1 = 14 15 | BS2 = 6 16 | 17 | for prescaler in range(4, 500): 18 | tq = float(prescaler)/pclk1 # [s] 19 | nominal_bittime = tq * (1 + BS1 + BS2) 20 | baud = 1.0/nominal_bittime 21 | if abs(((baud+500.0) % 1000.0) - 500.0) < 1.0: 22 | # Print only the baudrates with a even value. 23 | # (There may be a better way to write the test above...) 24 | print('%0.2f kBaud: can = CAN(1, CAN.NORMAL, prescaler=%d, bs1=%d, bs2=%d)' % (baud/1000.0, prescaler, BS1, BS2)) 25 | -------------------------------------------------------------------------------- /canbus_example/canbus_receiver_interrupt.py: -------------------------------------------------------------------------------- 1 | # https://github.com/hmaerki/micropython/tree/master/canbus_example 2 | 3 | from pyb import CAN 4 | from pyb import LED 5 | import micropython 6 | 7 | ledBlue = LED(1) 8 | 9 | IDs = (122, 123, 124, 125) 10 | 11 | # 50kBaud 12 | can = CAN(1, CAN.NORMAL, extframe=False, prescaler=40, sjw=1, bs1=14, bs2=6) 13 | can.setfilter(0, CAN.LIST16, 0, IDs) 14 | 15 | def my_handler_mainloop(reason): 16 | (id, isRTR, filterMatchIndex, telegram) = can.recv(0) 17 | print("received:", telegram) 18 | if telegram == b'on': 19 | ledBlue.on() 20 | else: 21 | ledBlue.off() 22 | 23 | def my_canbus_interrupt(bus, reason): 24 | # Don't handle code in the interrupt service routine. 25 | # Schedule a task to be handled soon 26 | if reason == 0: 27 | # print('pending') 28 | micropython.schedule(my_handler_mainloop, reason) 29 | return 30 | if reason == 1: 31 | print('full') 32 | return 33 | if reason == 2: 34 | print('overflow') 35 | return 36 | print('unknown') 37 | 38 | can.rxcallback(0, my_canbus_interrupt) 39 | 40 | print("Now listening on these CAN-id's: ", IDs) 41 | -------------------------------------------------------------------------------- /canbus_example/README.md: -------------------------------------------------------------------------------- 1 | # CAN-bus example application 2 | 3 | # How it works 4 | Two micropython boards are connected via a CAN bus. 5 | 6 | ## Sender 7 | - Pressing the *USER*-button will send `b'on'` to the CAN-id `123`. 8 | - Releasing the *USER*-button will send `b'off'` to the CAN-id `123`. 9 | 10 | ``` 11 | >>> import canbus_sender 12 | Press Switch to send CAN-telegrams, press to abort. 13 | sending b'on' to Id 123 14 | sending b'off' to Id 123 15 | sending b'on' to Id 123 16 | ``` 17 | 18 | ## Receiver 19 | - Waits for CAN-telegrams for CAN-ids `122`, `123`, `124` and `125`. 20 | - When a CAN-telegram arrives it switches the LED *on* if the telegram is `b'on'`. 21 | 22 | ``` 23 | >>> import canbus_receiver_interrupt 24 | Now listening on these CAN-id's: (122, 123, 124, 125) 25 | >>> received: b'on' 26 | received: b'off' 27 | received: b'on' 28 | ``` 29 | Note, that there is a `>>>` before `received: b'on'`. This indicates, that `import canbus_receiver_interrupt` returned and the command prompt is active again. But the interrupt handler is still active in the backgroud. 30 | 31 | # Implementation 32 | It is about the simplest program to demonstrate CAN-bus communication. 33 | 34 | There are two implementations of the receiver: 35 | - `canbus_receiver_polling.py` is polling in the main-loop. 36 | - `canbus_receiver_interrupt.py` gives the control back to the command prompt but a interrupts service is called whenever a CAN-telegram arrives. 37 | 38 | # Baud-Rate-Table 39 | The settings for the baudrates may be evaluated by the following script. 40 | **Note that the values are only valid for STM32F4 processors running on 168MHz.** 41 | ``` 42 | >>> import canbus_baudrate 43 | This is a pyboard version v1.9.4 on 2018-06-03. PYBv3 with STM32F405RG 44 | 1000.00 kBaud: can = CAN(1, CAN.NORMAL, prescaler=4, bs1=14, bs2=6) 45 | 800.00 kBaud: can = CAN(1, CAN.NORMAL, prescaler=5, bs1=14, bs2=6) 46 | 500.00 kBaud: can = CAN(1, CAN.NORMAL, prescaler=8, bs1=14, bs2=6) 47 | 400.00 kBaud: can = CAN(1, CAN.NORMAL, prescaler=10, bs1=14, bs2=6) 48 | 250.00 kBaud: can = CAN(1, CAN.NORMAL, prescaler=16, bs1=14, bs2=6) 49 | 200.00 kBaud: can = CAN(1, CAN.NORMAL, prescaler=20, bs1=14, bs2=6) 50 | 160.00 kBaud: can = CAN(1, CAN.NORMAL, prescaler=25, bs1=14, bs2=6) 51 | 125.00 kBaud: can = CAN(1, CAN.NORMAL, prescaler=32, bs1=14, bs2=6) 52 | 100.00 kBaud: can = CAN(1, CAN.NORMAL, prescaler=40, bs1=14, bs2=6) 53 | 80.00 kBaud: can = CAN(1, CAN.NORMAL, prescaler=50, bs1=14, bs2=6) 54 | 50.00 kBaud: can = CAN(1, CAN.NORMAL, prescaler=80, bs1=14, bs2=6) 55 | 40.00 kBaud: can = CAN(1, CAN.NORMAL, prescaler=100, bs1=14, bs2=6) 56 | 32.00 kBaud: can = CAN(1, CAN.NORMAL, prescaler=125, bs1=14, bs2=6) 57 | 25.00 kBaud: can = CAN(1, CAN.NORMAL, prescaler=160, bs1=14, bs2=6) 58 | 20.00 kBaud: can = CAN(1, CAN.NORMAL, prescaler=200, bs1=14, bs2=6) 59 | 16.00 kBaud: can = CAN(1, CAN.NORMAL, prescaler=250, bs1=14, bs2=6) 60 | 10.00 kBaud: can = CAN(1, CAN.NORMAL, prescaler=400, bs1=14, bs2=6) 61 | ``` 62 | 63 | 64 | # Schematic 65 | You need two external CAN-transceivers (one for the sender and one for the receiver board). I used [SN65HVD230 from TI](http://www.ti.com/lit/ds/symlink/sn65hvd230.pdf). 66 | 67 | ![CAN tranceiver](schematic/CAN_transceiver_schematic.png) 68 | 69 | --------------------------------------------------------------------------------