From d1b42d7b51c191d1ab3e44d712bc4b534b2d619e Mon Sep 17 00:00:00 2001
From: Damien George <damien.p.george@gmail.com>
Date: Sat, 15 Nov 2014 21:28:14 +0000
Subject: [PATCH] stmhal: Improve CAN init so that it can take sjw, bs1, bs2
 args.

Also update docs to explain how CAN baudrate is determined.
---
 docs/library/pyb.CAN.rst | 29 ++++++++++++++++++++++++++---
 stmhal/can.c             | 14 ++++----------
 stmhal/qstrdefsport.h    |  3 +++
 3 files changed, 33 insertions(+), 13 deletions(-)

diff --git a/docs/library/pyb.CAN.rst b/docs/library/pyb.CAN.rst
index 9ee5a0a69..094d26362 100644
--- a/docs/library/pyb.CAN.rst
+++ b/docs/library/pyb.CAN.rst
@@ -44,9 +44,32 @@ Methods
    Initialise the CAN bus with the given parameters:
    
      - ``mode`` is one of:  NORMAL, LOOPBACK, SILENT, SILENT_LOOPBACK
-
-   If ``extframe`` is True then the bus uses extended identifiers in the frames (29 bits).
-   Otherwise it uses standard 11 bit identifiers.
+     - if ``extframe`` is True then the bus uses extended identifiers in the frames
+       (29 bits); otherwise it uses standard 11 bit identifiers
+     - ``prescaler`` is used to set the duration of 1 time quanta; the time quanta
+       will be the input clock (PCLK1, see :meth:`pyb.freq()`) divided by the prescaler
+     - ``sjw`` is the resynchronisation jump width in units of the time quanta;
+       it can be 1, 2, 3, 4
+     - ``bs1`` defines the location of the sample point in units of the time quanta;
+       it can be between 1 and 1024 inclusive
+     - ``bs2`` defines the location of the transmit point in units of the time quanta;
+       it can be between 1 and 16 inclusive
+
+   The time quanta tq is the basic unit of time for the CAN bus.  tq is the CAN
+   prescaler value divided by PCLK1 (the frequency of internal peripheral bus 1);
+   see :meth:`pyb.freq()` to determine PCLK1.
+
+   A single bit is made up of the synchronisation segment, which is always 1 tq.
+   Then follows bit segment 1, then bit segment 2.  The sample point is after bit
+   segment 1 finishes.  The transmit point is after bit segment 2 finishes.
+   The baud rate will be 1/bittime, where the bittime is 1 + BS1 + BS2 multiplied
+   by the time quanta tq.
+
+   For example, with PCLK1=42MHz, prescaler=100, sjw=1, bs1=6, bs2=8, the value of
+   tq is 2.38 microseconds.  The bittime is 35.7 microseconds, and the baudrate
+   is 28kHz.
+
+   See page 680 of the STM32F405 datasheet for more details.
 
 .. method:: can.deinit()
 
diff --git a/stmhal/can.c b/stmhal/can.c
index de1ef3ecd..4b06b13ed 100644
--- a/stmhal/can.c
+++ b/stmhal/can.c
@@ -162,21 +162,15 @@ STATIC void pyb_can_print(void (*print)(void *env, const char *fmt, ...), void *
     }
 }
 
-/// \method init(mode, extframe=False, prescaler=100, *, sjw=1, bs1=6, bs2=8)
-///
-/// Initialise the CAN bus with the given parameters:
-///
-///   - `mode` is one of:  NORMAL, LOOPBACK, SILENT, SILENT_LOOPBACK
+// init(mode, extframe=False, prescaler=100, *, sjw=1, bs1=6, bs2=8)
 STATIC mp_obj_t pyb_can_init_helper(pyb_can_obj_t *self, mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
     static const mp_arg_t allowed_args[] = {
         { MP_QSTR_mode,         MP_ARG_REQUIRED | MP_ARG_INT,   {.u_int  = CAN_MODE_NORMAL} },
         { MP_QSTR_extframe,     MP_ARG_BOOL,                    {.u_bool = false} },
         { MP_QSTR_prescaler,    MP_ARG_INT,                     {.u_int  = 100} },
-        /*
         { MP_QSTR_sjw,          MP_ARG_KW_ONLY | MP_ARG_INT,    {.u_int = 1} },
         { MP_QSTR_bs1,          MP_ARG_KW_ONLY | MP_ARG_INT,    {.u_int = 6} },
         { MP_QSTR_bs2,          MP_ARG_KW_ONLY | MP_ARG_INT,    {.u_int = 8} },
-        */
     };
 
     // parse args
@@ -190,9 +184,9 @@ STATIC mp_obj_t pyb_can_init_helper(pyb_can_obj_t *self, mp_uint_t n_args, const
     CAN_InitTypeDef *init = &self->can.Init;
     init->Mode = args[0].u_int << 4; // shift-left so modes fit in a small-int
     init->Prescaler = args[2].u_int;
-    init->SJW = CAN_SJW_1TQ; // TODO set from args
-    init->BS1 = CAN_BS1_6TQ; // TODO set from args
-    init->BS2 = CAN_BS2_8TQ; // TODO set from args
+    init->SJW = ((args[3].u_int - 1) & 3) << 24;
+    init->BS1 = ((args[4].u_int - 1) & 0xf) << 16;
+    init->BS2 = ((args[5].u_int - 1) & 7) << 20;
     init->TTCM = DISABLE;
     init->ABOM = DISABLE;
     init->AWUM = DISABLE;
diff --git a/stmhal/qstrdefsport.h b/stmhal/qstrdefsport.h
index fc7942689..e7ef1ef29 100644
--- a/stmhal/qstrdefsport.h
+++ b/stmhal/qstrdefsport.h
@@ -171,6 +171,9 @@ Q(addr)
 Q(fifo)
 Q(timeout)
 Q(extframe)
+Q(sjw)
+Q(bs1)
+Q(bs2)
 Q(NORMAL)
 Q(LOOPBACK)
 Q(SILENT)
-- 
GitLab