Compare commits

7 Commits

11 changed files with 945 additions and 1722 deletions

View File

@@ -174,6 +174,107 @@
)
)
)
(symbol "Connector:Screw_Terminal_01x03" (pin_names (offset 1.016) hide) (in_bom yes) (on_board yes)
(property "Reference" "J" (at 0 5.08 0)
(effects (font (size 1.27 1.27)))
)
(property "Value" "Screw_Terminal_01x03" (at 0 -5.08 0)
(effects (font (size 1.27 1.27)))
)
(property "Footprint" "" (at 0 0 0)
(effects (font (size 1.27 1.27)) hide)
)
(property "Datasheet" "~" (at 0 0 0)
(effects (font (size 1.27 1.27)) hide)
)
(property "ki_keywords" "screw terminal" (at 0 0 0)
(effects (font (size 1.27 1.27)) hide)
)
(property "ki_description" "Generic screw terminal, single row, 01x03, script generated (kicad-library-utils/schlib/autogen/connector/)" (at 0 0 0)
(effects (font (size 1.27 1.27)) hide)
)
(property "ki_fp_filters" "TerminalBlock*:*" (at 0 0 0)
(effects (font (size 1.27 1.27)) hide)
)
(symbol "Screw_Terminal_01x03_1_1"
(rectangle (start -1.27 3.81) (end 1.27 -3.81)
(stroke (width 0.254) (type default))
(fill (type background))
)
(circle (center 0 -2.54) (radius 0.635)
(stroke (width 0.1524) (type default))
(fill (type none))
)
(polyline
(pts
(xy -0.5334 -2.2098)
(xy 0.3302 -3.048)
)
(stroke (width 0.1524) (type default))
(fill (type none))
)
(polyline
(pts
(xy -0.5334 0.3302)
(xy 0.3302 -0.508)
)
(stroke (width 0.1524) (type default))
(fill (type none))
)
(polyline
(pts
(xy -0.5334 2.8702)
(xy 0.3302 2.032)
)
(stroke (width 0.1524) (type default))
(fill (type none))
)
(polyline
(pts
(xy -0.3556 -2.032)
(xy 0.508 -2.8702)
)
(stroke (width 0.1524) (type default))
(fill (type none))
)
(polyline
(pts
(xy -0.3556 0.508)
(xy 0.508 -0.3302)
)
(stroke (width 0.1524) (type default))
(fill (type none))
)
(polyline
(pts
(xy -0.3556 3.048)
(xy 0.508 2.2098)
)
(stroke (width 0.1524) (type default))
(fill (type none))
)
(circle (center 0 0) (radius 0.635)
(stroke (width 0.1524) (type default))
(fill (type none))
)
(circle (center 0 2.54) (radius 0.635)
(stroke (width 0.1524) (type default))
(fill (type none))
)
(pin passive line (at -5.08 2.54 0) (length 3.81)
(name "Pin_1" (effects (font (size 1.27 1.27))))
(number "1" (effects (font (size 1.27 1.27))))
)
(pin passive line (at -5.08 0 0) (length 3.81)
(name "Pin_2" (effects (font (size 1.27 1.27))))
(number "2" (effects (font (size 1.27 1.27))))
)
(pin passive line (at -5.08 -2.54 0) (length 3.81)
(name "Pin_3" (effects (font (size 1.27 1.27))))
(number "3" (effects (font (size 1.27 1.27))))
)
)
)
(symbol "Device:Battery" (pin_numbers hide) (pin_names (offset 0) hide) (in_bom yes) (on_board yes)
(property "Reference" "BT" (at 2.54 2.54 0)
(effects (font (size 1.27 1.27)) (justify left))
@@ -1549,7 +1650,14 @@
)
)
(junction (at 120.65 39.37) (diameter 0) (color 0 0 0 0)
(uuid 8c2a9d2a-1d4e-4579-9c59-afc6ca005a71)
)
(wire (pts (xy 66.04 29.21) (xy 66.04 54.61))
(stroke (width 0) (type default))
(uuid 01f524af-11c1-4c17-99e1-c2944d69a8f7)
)
(wire (pts (xy 72.39 92.71) (xy 81.28 92.71))
(stroke (width 0) (type default))
(uuid 05b01c7e-4127-4d37-b284-7eaaacb6c7dc)
@@ -1570,6 +1678,14 @@
(stroke (width 0) (type default))
(uuid 1b3c181c-7296-4f46-89bc-4ff9b3f70693)
)
(wire (pts (xy 66.04 54.61) (xy 63.5 54.61))
(stroke (width 0) (type default))
(uuid 1dbd1db0-a438-4cfa-bf68-4c72dcdd5f56)
)
(wire (pts (xy 67.31 39.37) (xy 67.31 57.15))
(stroke (width 0) (type default))
(uuid 1f5d925b-60d0-4369-98dc-3846c9d9c573)
)
(wire (pts (xy 199.39 48.26) (xy 199.39 53.34))
(stroke (width 0) (type default))
(uuid 216ec0ab-0c53-4f35-b412-236b880d6be1)
@@ -1602,14 +1718,26 @@
(stroke (width 0) (type default))
(uuid 4098c331-b1b2-4ad1-a747-832669d10861)
)
(wire (pts (xy 120.65 39.37) (xy 120.65 29.21))
(stroke (width 0) (type default))
(uuid 464fa9ba-8ee8-46f6-931b-9ca742ee7f83)
)
(wire (pts (xy 45.72 87.63) (xy 46.99 87.63))
(stroke (width 0) (type default))
(uuid 4f2751f5-fe28-4846-a677-7f191f486af8)
)
(wire (pts (xy 81.28 97.79) (xy 72.39 97.79))
(stroke (width 0) (type default))
(uuid 51354f6c-6941-42e5-b234-59e81723d642)
)
(wire (pts (xy 194.31 57.15) (xy 158.75 57.15))
(stroke (width 0) (type default))
(uuid 5612e8eb-b51d-41d0-90e2-f7bda0a0b35e)
)
(wire (pts (xy 59.69 100.33) (xy 72.39 100.33))
(stroke (width 0) (type default))
(uuid 627ab450-99a0-4c25-8cb0-c006c8c75e70)
)
(wire (pts (xy 130.81 59.69) (xy 130.81 41.91))
(stroke (width 0) (type default))
(uuid 693c60a8-b000-4c9f-b47d-9c5cdaafdc7d)
@@ -1618,6 +1746,10 @@
(stroke (width 0) (type default))
(uuid 721840aa-deee-40ff-990c-bb1e7ba7df9d)
)
(wire (pts (xy 67.31 39.37) (xy 110.49 39.37))
(stroke (width 0) (type default))
(uuid 75e66abc-9688-4acc-9c3a-a2757475cab4)
)
(wire (pts (xy 140.97 45.72) (xy 140.97 59.69))
(stroke (width 0) (type default))
(uuid 7b443fa6-a84c-4666-9057-189de3b33013)
@@ -1626,6 +1758,10 @@
(stroke (width 0) (type default))
(uuid 80af2744-85de-4432-b310-bf5ac285253a)
)
(wire (pts (xy 63.5 59.69) (xy 81.28 59.69))
(stroke (width 0) (type default))
(uuid 810f483f-b3a8-48d0-9096-c1a0bd61fea4)
)
(wire (pts (xy 218.44 66.04) (xy 218.44 73.66))
(stroke (width 0) (type default))
(uuid 811a6c7a-675a-48ca-8849-d2709801394e)
@@ -1638,10 +1774,6 @@
(stroke (width 0) (type default))
(uuid a0a45fc4-23a8-4535-a6b2-71a9726b5116)
)
(wire (pts (xy 59.69 102.87) (xy 81.28 102.87))
(stroke (width 0) (type default))
(uuid a1883311-7ef7-4151-bb39-266bb1e72a94)
)
(wire (pts (xy 194.31 99.06) (xy 194.31 59.69))
(stroke (width 0) (type default))
(uuid a363f041-a45f-46cf-9b88-1df1f6c86a42)
@@ -1650,9 +1782,13 @@
(stroke (width 0) (type default))
(uuid a71679c3-e533-43d6-8c41-7bb3f8b1ff39)
)
(wire (pts (xy 59.69 102.87) (xy 59.69 100.33))
(wire (pts (xy 120.65 29.21) (xy 66.04 29.21))
(stroke (width 0) (type default))
(uuid ae9e9053-68e5-4e36-abbd-fc2cb8f70796)
(uuid a7259b14-9f2b-49b7-a5c3-c20a3919fa38)
)
(wire (pts (xy 63.5 57.15) (xy 67.31 57.15))
(stroke (width 0) (type default))
(uuid a8dfd664-837a-49bf-8c19-d02781874610)
)
(wire (pts (xy 140.97 59.69) (xy 144.78 59.69))
(stroke (width 0) (type default))
@@ -1698,6 +1834,10 @@
(stroke (width 0) (type default))
(uuid e04d2ba8-e916-477a-90e3-68e85e9b6591)
)
(wire (pts (xy 72.39 97.79) (xy 72.39 100.33))
(stroke (width 0) (type default))
(uuid ed5d8e8f-a82e-4e92-8752-8e2bb74c9fce)
)
(wire (pts (xy 45.72 92.71) (xy 46.99 92.71))
(stroke (width 0) (type default))
(uuid f558eace-bfda-4a86-b67f-d00acdf64350)
@@ -2149,6 +2289,33 @@
)
)
(symbol (lib_id "Connector:Screw_Terminal_01x03") (at 58.42 57.15 180) (unit 1)
(in_bom yes) (on_board yes) (dnp no) (fields_autoplaced)
(uuid c72c4908-aaa8-4267-a4cb-ad8b1938ac58)
(property "Reference" "J3" (at 58.42 48.26 0)
(effects (font (size 1.27 1.27)))
)
(property "Value" "Screw_Terminal_01x03" (at 58.42 50.8 0)
(effects (font (size 1.27 1.27)))
)
(property "Footprint" "" (at 58.42 57.15 0)
(effects (font (size 1.27 1.27)) hide)
)
(property "Datasheet" "~" (at 58.42 57.15 0)
(effects (font (size 1.27 1.27)) hide)
)
(pin "3" (uuid 0d5487a7-69b1-48ee-a45e-c8b927e188ec))
(pin "2" (uuid 69814f47-2522-4a93-8046-a72904af0d1e))
(pin "1" (uuid 0136f772-aa81-4679-8cc6-4f761551470f))
(instances
(project "CANBoard"
(path "/a9e196b8-03ab-4286-acfa-8467590acf68"
(reference "J3") (unit 1)
)
)
)
)
(symbol (lib_id "Device:Battery") (at 218.44 78.74 0) (unit 1)
(in_bom yes) (on_board yes) (dnp no) (fields_autoplaced)
(uuid cfbba8f3-bef6-4c10-b497-eb67e272a7fe)

16
CANBoard/Makefile Normal file
View File

@@ -0,0 +1,16 @@
clean:
pio run -t clean
build:
pio run --verbose
flash: build
gdb -nx --batch \
-ex 'target extended-remote /dev/ttyACM0' \
-ex 'monitor swdp_scan' \
-ex 'attach 1' \
-ex 'load' \
-ex 'compare-sections' \
-ex 'kill' \
./.pio/build/bluepill_f103c8/firmware.elf

11
CANBoard/README.md Normal file
View File

@@ -0,0 +1,11 @@
# To compile
```sh
make build
```
# To flash with a Black Magic Debug probe
```sh
make flash
```

View File

@@ -9,7 +9,7 @@
; https://docs.platformio.org/page/projectconf.html
[platformio]
[env:bluepill_gd32f103c8]
platform = gd32
framework = spl
board = genericGD32F103C8
[env:bluepill_f103c8]
platform = ststm32
framework = arduino
board = bluepill_f103c8

View File

@@ -1,2 +0,0 @@
int main() {
}

722
CANBoard/src/main.cpp Normal file
View File

@@ -0,0 +1,722 @@
#include <Arduino.h>
HardwareSerial Serial3(PB11, PB10);
#include <stdlib.h>
#include <assert.h>
#include "main.h"
uint8_t line[USER_INPUT_BUFFER_SIZE]; //Stores user text as it's read from serial buffer
#define DEBUG 1
/* Symbolic names for bit rate of CAN message */
typedef enum {CAN_50KBPS, CAN_100KBPS, CAN_125KBPS, CAN_250KBPS, CAN_500KBPS, CAN_1000KBPS} BITRATE;
/* Real speed for bit rate of CAN message */
uint32_t SPEED[6] = {50*1000, 100*1000, 125*1000, 250*1000, 500*1000, 1000*1000};
/* Symbolic names for formats of CAN message */
typedef enum {STANDARD_FORMAT = 0, EXTENDED_FORMAT} CAN_FORMAT;
/* Symbolic names for type of CAN message */
typedef enum {DATA_FRAME = 0, REMOTE_FRAME} CAN_FRAME;
typedef struct
{
uint32_t id; /* 29 bit identifier */
uint8_t data[8]; /* Data field */
uint8_t len; /* Length of data field in bytes */
uint8_t ch; /* Object channel(Not use) */
uint8_t format; /* 0 - STANDARD, 1- EXTENDED IDENTIFIER */
uint8_t type; /* 0 - DATA FRAME, 1 - REMOTE FRAME */
} CAN_msg_t;
typedef struct
{
uint16_t baud_rate_prescaler; /// [1 to 1024]
uint8_t time_segment_1; /// [1 to 16]
uint8_t time_segment_2; /// [1 to 8]
uint8_t resynchronization_jump_width; /// [1 to 4] (recommended value is 1)
} CAN_bit_timing_config_t;
#define CAN_STM32_ERROR_UNSUPPORTED_BIT_RATE 1000
#define CAN_STM32_ERROR_MSR_INAK_NOT_SET 1001
#define CAN_STM32_ERROR_MSR_INAK_NOT_CLEARED 1002
#define CAN_STM32_ERROR_UNSUPPORTED_FRAME_FORMAT 1003
/*
* Calculation of bit timing dependent on peripheral clock rate
*/
int16_t ComputeCANTimings(const uint32_t peripheral_clock_rate,
const uint32_t target_bitrate,
CAN_bit_timing_config_t* const out_timings)
{
if (target_bitrate < 1000)
{
return -CAN_STM32_ERROR_UNSUPPORTED_BIT_RATE;
}
assert(out_timings != NULL); // NOLINT
memset(out_timings, 0, sizeof(*out_timings));
/*
* Hardware configuration
*/
static const uint8_t MaxBS1 = 16;
static const uint8_t MaxBS2 = 8;
/*
* Ref. "Automatic Baudrate Detection in CANopen Networks", U. Koppe, MicroControl GmbH & Co. KG
* CAN in Automation, 2003
*
* According to the source, optimal quanta per bit are:
* Bitrate Optimal Maximum
* 1000 kbps 8 10
* 500 kbps 16 17
* 250 kbps 16 17
* 125 kbps 16 17
*/
const uint8_t max_quanta_per_bit = (uint8_t)((target_bitrate >= 1000000) ? 10 : 17); // NOLINT
assert(max_quanta_per_bit <= (MaxBS1 + MaxBS2));
static const uint16_t MaxSamplePointLocationPermill = 900;
/*
* Computing (prescaler * BS):
* BITRATE = 1 / (PRESCALER * (1 / PCLK) * (1 + BS1 + BS2)) -- See the Reference Manual
* BITRATE = PCLK / (PRESCALER * (1 + BS1 + BS2)) -- Simplified
* let:
* BS = 1 + BS1 + BS2 -- Number of time quanta per bit
* PRESCALER_BS = PRESCALER * BS
* ==>
* PRESCALER_BS = PCLK / BITRATE
*/
const uint32_t prescaler_bs = peripheral_clock_rate / target_bitrate;
/*
* Searching for such prescaler value so that the number of quanta per bit is highest.
*/
uint8_t bs1_bs2_sum = (uint8_t)(max_quanta_per_bit - 1); // NOLINT
while ((prescaler_bs % (1U + bs1_bs2_sum)) != 0)
{
if (bs1_bs2_sum <= 2)
{
return -CAN_STM32_ERROR_UNSUPPORTED_BIT_RATE; // No solution
}
bs1_bs2_sum--;
}
const uint32_t prescaler = prescaler_bs / (1U + bs1_bs2_sum);
if ((prescaler < 1U) || (prescaler > 1024U))
{
return -CAN_STM32_ERROR_UNSUPPORTED_BIT_RATE; // No solution
}
/*
* Now we have a constraint: (BS1 + BS2) == bs1_bs2_sum.
* We need to find such values so that the sample point is as close as possible to the optimal value,
* which is 87.5%, which is 7/8.
*
* Solve[(1 + bs1)/(1 + bs1 + bs2) == 7/8, bs2] (* Where 7/8 is 0.875, the recommended sample point location *)
* {{bs2 -> (1 + bs1)/7}}
*
* Hence:
* bs2 = (1 + bs1) / 7
* bs1 = (7 * bs1_bs2_sum - 1) / 8
*
* Sample point location can be computed as follows:
* Sample point location = (1 + bs1) / (1 + bs1 + bs2)
*
* Since the optimal solution is so close to the maximum, we prepare two solutions, and then pick the best one:
* - With rounding to nearest
* - With rounding to zero
*/
uint8_t bs1 = (uint8_t)(((7 * bs1_bs2_sum - 1) + 4) / 8); // Trying rounding to nearest first // NOLINT
uint8_t bs2 = (uint8_t)(bs1_bs2_sum - bs1); // NOLINT
assert(bs1_bs2_sum > bs1);
{
const uint16_t sample_point_permill = (uint16_t)(1000U * (1U + bs1) / (1U + bs1 + bs2)); // NOLINT
if (sample_point_permill > MaxSamplePointLocationPermill) // Strictly more!
{
bs1 = (uint8_t)((7 * bs1_bs2_sum - 1) / 8); // Nope, too far; now rounding to zero
bs2 = (uint8_t)(bs1_bs2_sum - bs1);
}
}
const bool valid = (bs1 >= 1) && (bs1 <= MaxBS1) && (bs2 >= 1) && (bs2 <= MaxBS2);
/*
* Final validation
* Helpful Python:
* def sample_point_from_btr(x):
* assert 0b0011110010000000111111000000000 & x == 0
* ts2,ts1,brp = (x>>20)&7, (x>>16)&15, x&511
* return (1+ts1+1)/(1+ts1+1+ts2+1)
*/
if ((target_bitrate != (peripheral_clock_rate / (prescaler * (1U + bs1 + bs2)))) ||
!valid)
{
// This actually means that the algorithm has a logic error, hence assert(0).
assert(0); // NOLINT
return -CAN_STM32_ERROR_UNSUPPORTED_BIT_RATE;
}
out_timings->baud_rate_prescaler = (uint16_t) prescaler;
out_timings->resynchronization_jump_width = 1; // One is recommended by UAVCAN, CANOpen, and DeviceNet
out_timings->time_segment_1 = bs1;
out_timings->time_segment_2 = bs2;
if (DEBUG) {
Serial3.print("target_bitrate=");
Serial3.println(target_bitrate);
Serial3.print("peripheral_clock_rate=");
Serial3.println(peripheral_clock_rate);
Serial3.print("timings.baud_rate_prescaler=");
Serial3.println(out_timings->baud_rate_prescaler);
Serial3.print("timings.time_segment_1=");
Serial3.println(out_timings->time_segment_1);
Serial3.print("timings.time_segment_2=");
Serial3.println(out_timings->time_segment_2);
Serial3.print("timings.resynchronization_jump_width=");
Serial3.println(out_timings->resynchronization_jump_width);
}
return 0;
}
/**
* Print registers.
*/
void printRegister(const char * buf, uint32_t reg) {
if (DEBUG == 0) return;
Serial3.print(buf);
Serial3.print(reg, HEX);
Serial3.println();
}
/**
* Initializes the CAN filter registers.
*
* @preconditions - This register can be written only when the filter initialization mode is set (FINIT=1) in the CAN_FMR register.
* @params: index - Specified filter index. index 27:14 are available in connectivity line devices only.
* @params: scale - Select filter scale.
* 0: Dual 16-bit scale configuration
* 1: Single 32-bit scale configuration
* @params: mode - Select filter mode.
* 0: Two 32-bit registers of filter bank x are in Identifier Mask mode
* 1: Two 32-bit registers of filter bank x are in Identifier List mode
* @params: fifo - Select filter assigned.
* 0: Filter assigned to FIFO 0
* 1: Filter assigned to FIFO 1
* @params: bank1 - Filter bank register 1
* @params: bank2 - Filter bank register 2
*
*/
void CANSetFilter(uint8_t index, uint8_t scale, uint8_t mode, uint8_t fifo, uint32_t bank1, uint32_t bank2) {
if (index > 27) return;
CAN1->FA1R &= ~(0x1UL<<index); // Deactivate filter
if (scale == 0) {
CAN1->FS1R &= ~(0x1UL<<index); // Set filter to Dual 16-bit scale configuration
} else {
CAN1->FS1R |= (0x1UL<<index); // Set filter to single 32 bit configuration
}
if (mode == 0) {
CAN1->FM1R &= ~(0x1UL<<index); // Set filter to Mask mode
} else {
CAN1->FM1R |= (0x1UL<<index); // Set filter to List mode
}
if (fifo == 0) {
CAN1->FFA1R &= ~(0x1UL<<index); // Set filter assigned to FIFO 0
} else {
CAN1->FFA1R |= (0x1UL<<index); // Set filter assigned to FIFO 1
}
CAN1->sFilterRegister[index].FR1 = bank1; // Set filter bank registers1
CAN1->sFilterRegister[index].FR2 = bank2; // Set filter bank registers2
CAN1->FA1R |= (0x1UL<<index); // Activate filter
}
/**
* Initializes the CAN controller with specified bit rate.
*
* @params: bitrate - Specified bitrate. If this value is not one of the defined constants, bit rate will be defaulted to 125KBS
* @params: remap - Select CAN port.
* =0:CAN_RX mapped to PA11, CAN_TX mapped to PA12
* =1:Not used
* =2:CAN_RX mapped to PB8, CAN_TX mapped to PB9 (not available on 36-pin package)
* =3:CAN_RX mapped to PD0, CAN_TX mapped to PD1 (available on 100-pin and 144-pin package)
*
*/
bool CANInit(BITRATE bitrate, int remap)
{
// Reference manual
// https://www.st.com/content/ccc/resource/technical/document/reference_manual/59/b9/ba/7f/11/af/43/d5/CD00171190.pdf/files/CD00171190.pdf/jcr:content/translations/en.CD00171190.pdf
RCC->APB1ENR |= 0x2000000UL; // Enable CAN clock
RCC->APB2ENR |= 0x1UL; // Enable AFIO clock
AFIO->MAPR &= 0xFFFF9FFF; // reset CAN remap
// CAN_RX mapped to PA11, CAN_TX mapped to PA12
if (remap == 0) {
RCC->APB2ENR |= 0x4UL; // Enable GPIOA clock
GPIOA->CRH &= ~(0xFF000UL); // Configure PA12(0b0000) and PA11(0b0000)
// 0b0000
// MODE=00(Input mode)
// CNF=00(Analog mode)
GPIOA->CRH |= 0xB8FFFUL; // Configure PA12(0b1011) and PA11(0b1000)
// 0b1011
// MODE=11(Output mode, max speed 50 MHz)
// CNF=10(Alternate function output Push-pull
// 0b1000
// MODE=00(Input mode)
// CNF=10(Input with pull-up / pull-down)
//GPIOA->ODR |= 0x1UL << 12; // PA12 Upll-up
GPIOA->ODR |= 0x1UL << 11; // PA11 Upll-up
}
if (remap == 2) {
AFIO->MAPR |= 0x00004000; // set CAN remap
// CAN_RX mapped to PB8, CAN_TX mapped to PB9 (not available on 36-pin package)
RCC->APB2ENR |= 0x8UL; // Enable GPIOB clock
GPIOB->CRH &= ~(0xFFUL); // Configure PB9(0b0000) and PB8(0b0000)
// 0b0000
// MODE=00(Input mode)
// CNF=00(Analog mode)
GPIOB->CRH |= 0xB8UL; // Configure PB9(0b1011) and PB8(0b1000)
// 0b1011
// MODE=11(Output mode, max speed 50 MHz)
// CNF=10(Alternate function output Push-pull
// 0b1000
// MODE=00(Input mode)
// CNF=10(Input with pull-up / pull-down)
GPIOB->ODR |= 0x1UL << 8; // PB8 Upll-up
}
if (remap == 3) {
AFIO->MAPR |= 0x00005000; // set CAN remap
// CAN_RX mapped to PD0, CAN_TX mapped to PD1 (available on 100-pin and 144-pin package)
RCC->APB2ENR |= 0x20UL; // Enable GPIOD clock
GPIOD->CRL &= ~(0xFFUL); // Configure PD1(0b0000) and PD0(0b0000)
// 0b0000
// MODE=00(Input mode)
// CNF=00(Analog mode)
GPIOD->CRH |= 0xB8UL; // Configure PD1(0b1011) and PD0(0b1000)
// 0b1000
// MODE=00(Input mode)
// CNF=10(Input with pull-up / pull-down)
// 0b1011
// MODE=11(Output mode, max speed 50 MHz)
// CNF=10(Alternate function output Push-pull
GPIOD->ODR |= 0x1UL << 0; // PD0 Upll-up
}
CAN1->MCR &= ~0x2UL; // Require CAN1 leave sleep mode
CAN1->MCR |= 0x1UL; // Require CAN1 to Initialization mode
while (!(CAN1->MSR & 0x1UL)) { // Wait for Initialization mode
#ifdef DEBUG
Serial3.println(CAN1->MSR,HEX); // Wait for Initialization mode
Serial3.println(CAN1->ESR,HEX); // Wait for Initialization mode
#endif
}
CAN1->MCR = 0x41UL; // Hardware initialization(With automatic retransmission)
// file:///home/mkennedy/Downloads/rm0008-stm32f101xx-stm32f102xx-stm32f103xx-stm32f105xx-and-stm32f107xx-advanced-armbased-32bit-mcus-stmicroelectronics.pdf#page=686
// http://www.internetsomething.com/autoolx50/GD32F10x_User_Manual_EN_V2.0.pdf#page=646
// Set bit timing register
CAN_bit_timing_config_t timings;
Serial3.print("bitrate=");
Serial3.println(bitrate);
uint32_t target_bitrate = SPEED[bitrate];
Serial3.print("target_bitrate=");
Serial3.println(target_bitrate);
int result = ComputeCANTimings(HAL_RCC_GetPCLK1Freq(), target_bitrate, &timings);
Serial3.print("ComputeCANTimings result=");
Serial3.println(result);
if (result) while(true);
CAN1->BTR = (((timings.resynchronization_jump_width - 1U) & 3U) << 24U) |
(((timings.time_segment_1 - 1U) & 15U) << 16U) |
(((timings.time_segment_2 - 1U) & 7U) << 20U) |
((timings.baud_rate_prescaler - 1U) & 1023U);
// Configure Filters to default values
CAN1->FMR |= 0x1UL; // Set to filter initialization mode
CAN1->FMR &= 0xFFFFC0FF; // Clear CAN2 start bank
// bxCAN has 28 filters.
// These filters are shared by both CAN1 and CAN2.
// STM32F103 has only CAN1, so all 28 are used for CAN1
CAN1->FMR |= 0x1C << 8; // Assign all filters to CAN1
// Set fileter 0
// Single 32-bit scale configuration
// Two 32-bit registers of filter bank x are in Identifier Mask mode
// Filter assigned to FIFO 0
// Filter bank register to all 0
CANSetFilter(0, 1, 0, 0, 0x0UL, 0x0UL);
CAN1->FMR &= ~(0x1UL); // Deactivate initialization mode
uint16_t TimeoutMilliseconds = 1000;
bool can1 = false;
CAN1->MCR &= ~(0x1UL); // Require CAN1 to normal mode
// Wait for normal mode
// If the connection is not correct, it will not return to normal mode.
for (uint16_t wait_ack = 0; wait_ack < TimeoutMilliseconds; wait_ack++) {
if ((CAN1->MSR & 0x1UL) == 0) {
can1 = true;
break;
}
delayMicroseconds(1000);
}
//Serial3.print("can1=");
//Serial3.println(can1);
if (can1) {
Serial3.println("CAN1 initialize ok");
} else {
Serial3.println("CAN1 initialize fail!!");
return false;
}
return true;
}
#define STM32_CAN_TIR_TXRQ (1U << 0U) // Bit 0: Transmit Mailbox Request
#define STM32_CAN_RIR_RTR (1U << 1U) // Bit 1: Remote Transmission Request
#define STM32_CAN_RIR_IDE (1U << 2U) // Bit 2: Identifier Extension
#define STM32_CAN_TIR_RTR (1U << 1U) // Bit 1: Remote Transmission Request
#define STM32_CAN_TIR_IDE (1U << 2U) // Bit 2: Identifier Extension
#define CAN_EXT_ID_MASK 0x1FFFFFFFU
#define CAN_STD_ID_MASK 0x000007FFU
/////////////////////////////////////////////////////////////////////////////////////////////
/**
* Decodes CAN messages from the data registers and populates a
* CAN message struct with the data fields.
*
* @preconditions A valid CAN message is received
* @params CAN_rx_msg - CAN message structure for reception
*
*/
void CANReceive(CAN_msg_t* CAN_rx_msg)
{
uint32_t id = CAN1->sFIFOMailBox[0].RIR;
if ((id & STM32_CAN_RIR_IDE) == 0) { // Standard frame format
CAN_rx_msg->format = STANDARD_FORMAT;;
CAN_rx_msg->id = (CAN_STD_ID_MASK & (id >> 21U));
}
else { // Extended frame format
CAN_rx_msg->format = EXTENDED_FORMAT;;
CAN_rx_msg->id = (CAN_EXT_ID_MASK & (id >> 3U));
}
if ((id & STM32_CAN_RIR_RTR) == 0) { // Data frame
CAN_rx_msg->type = DATA_FRAME;
}
else { // Remote frame
CAN_rx_msg->type = REMOTE_FRAME;
}
CAN_rx_msg->len = (CAN1->sFIFOMailBox[0].RDTR) & 0xFUL;
CAN_rx_msg->data[0] = 0xFFUL & CAN1->sFIFOMailBox[0].RDLR;
CAN_rx_msg->data[1] = 0xFFUL & (CAN1->sFIFOMailBox[0].RDLR >> 8);
CAN_rx_msg->data[2] = 0xFFUL & (CAN1->sFIFOMailBox[0].RDLR >> 16);
CAN_rx_msg->data[3] = 0xFFUL & (CAN1->sFIFOMailBox[0].RDLR >> 24);
CAN_rx_msg->data[4] = 0xFFUL & CAN1->sFIFOMailBox[0].RDHR;
CAN_rx_msg->data[5] = 0xFFUL & (CAN1->sFIFOMailBox[0].RDHR >> 8);
CAN_rx_msg->data[6] = 0xFFUL & (CAN1->sFIFOMailBox[0].RDHR >> 16);
CAN_rx_msg->data[7] = 0xFFUL & (CAN1->sFIFOMailBox[0].RDHR >> 24);
// Release FIFO 0 output mailbox.
// Make the next incoming message available.
CAN1->RF0R |= 0x20UL;
}
/////////////////////////////////////////////////////////////////////////////////////////////
/**
* Encodes CAN messages using the CAN message struct and populates the
* data registers with the sent.
*
* @params CAN_tx_msg - CAN message structure for transmission
*
*/
void CANSend(CAN_msg_t* CAN_tx_msg)
{
volatile int count = 0;
uint32_t out = 0;
if (CAN_tx_msg->format == EXTENDED_FORMAT) { // Extended frame format
out = ((CAN_tx_msg->id & CAN_EXT_ID_MASK) << 3U) | STM32_CAN_TIR_IDE;
}
else { // Standard frame format
out = ((CAN_tx_msg->id & CAN_STD_ID_MASK) << 21U);
}
// Remote frame
if (CAN_tx_msg->type == REMOTE_FRAME) {
out |= STM32_CAN_TIR_RTR;
}
CAN1->sTxMailBox[0].TDTR &= ~(0xF);
CAN1->sTxMailBox[0].TDTR |= CAN_tx_msg->len & 0xFUL;
CAN1->sTxMailBox[0].TDLR = (((uint32_t) CAN_tx_msg->data[3] << 24) |
((uint32_t) CAN_tx_msg->data[2] << 16) |
((uint32_t) CAN_tx_msg->data[1] << 8) |
((uint32_t) CAN_tx_msg->data[0] ));
CAN1->sTxMailBox[0].TDHR = (((uint32_t) CAN_tx_msg->data[7] << 24) |
((uint32_t) CAN_tx_msg->data[6] << 16) |
((uint32_t) CAN_tx_msg->data[5] << 8) |
((uint32_t) CAN_tx_msg->data[4] ));
// Send Go
CAN1->sTxMailBox[0].TIR = out | STM32_CAN_TIR_TXRQ;
// Wait until the mailbox is empty
while(CAN1->sTxMailBox[0].TIR & 0x1UL && count++ < 1000000);
// The mailbox don't becomes empty while loop
if (CAN1->sTxMailBox[0].TIR & 0x1UL) {
Serial3.println("Send Fail");
Serial3.println(CAN1->ESR, HEX);
Serial3.println(CAN1->MSR, HEX);
Serial3.println(CAN1->TSR, HEX);
}
}
/////////////////////////////////////////////////////////////////////////////////////////////
/**
* Returns whether there are CAN messages available.
*
* @returns If pending CAN messages are in the CAN controller
*
*/
uint8_t CANMsgAvail(void)
{
// Check for pending FIFO 0 messages
return CAN1->RF0R & 0x3UL;
}
/////////////////////////////////////////////////////////////////////////////////////////////
uint8_t counter = 0;
uint8_t frameLength = 0;
unsigned long previousMillis = 0; // stores last time output was updated
const long interval = 100; // transmission interval (milliseconds)
/////////////////////////////////////////////////////////////////////////////////////////////
void CheckCANRxAndHandle() {
CAN_msg_t CAN_RX_msg;
if(CANMsgAvail()) {
CANReceive(&CAN_RX_msg);
if (CAN_RX_msg.id < 0x100) Serial3.print("0");
if (CAN_RX_msg.id < 0x10) Serial3.print("0");
Serial3.print(CAN_RX_msg.id, HEX);
Serial3.print("#");
if (CAN_RX_msg.type == DATA_FRAME) {
for(int i=0; i<CAN_RX_msg.len; i++) {
if (CAN_RX_msg.data[i] < 0x10) Serial3.print("0");
Serial3.print(CAN_RX_msg.data[i], HEX);
}
Serial3.println();
} else {
Serial3.println(" Data: REMOTE REQUEST FRAME");
}
}
}
/////////////////////////////////////////////////////////////////////////////////////////////
void printHelp(void)
{
Serial3.print(F("\n\nCANBoard commands:"
"\n\r -'$BOOTX'. Boot board X."
"\n\r -'$HELP'. Print this help."
"\n\r"
));
}
/////////////////////////////////////////////////////////////////////////////////////////////
void boot1(void)
{
digitalWrite(PB14, LOW);
delay(10);
digitalWrite(PB14, HIGH);
}
/////////////////////////////////////////////////////////////////////////////////////////////
void kill1(void)
{
digitalWrite(PB14, LOW);
}
/////////////////////////////////////////////////////////////////////////////////////////////
//determine which command to run
void USB_userInterface_executeUserInput(void)
{
if(line[0] == '$') //valid commands start with '$'
{
//$HELP
if( (line[1] == 'H') && (line[2] == 'E') && (line[3] == 'L') && (line[4] == 'P') ) { printHelp(); return; }
if( (line[1] == 'B') && (line[2] == 'O') && (line[3] == 'O') && (line[4] == 'T') ) {
if ( (line[5] == '1') ) {
boot1();
return;
}
}
if( (line[1] == 'K') && (line[2] == 'I') && (line[3] == 'L') && (line[4] == 'L') ) {
if ( (line[5] == '1') ) {
kill1();
return;
}
}
}
Serial3.println(F("\nInvalid Entry"));
}
/////////////////////////////////////////////////////////////////////////////////////////////
void printStringStoredInArray(const uint8_t *s)
{
while (*s) { Serial3.write(*s++); } //write each character until '0' (EOL character)
}
/////////////////////////////////////////////////////////////////////////////////////////////
//read user-typed input from serial buffer
//user input executes at each newline character
void USB_userInterface_handler(void)
{
uint8_t latestCharacterRead = 0; //c
static uint8_t numCharactersReceived = 0; //char_counter
static uint8_t inputFlags = 0; //stores state as input text is processed (e.g. whether inside a comment or not)
while( Serial3.available() )
{
//user-typed characters are waiting in serial buffer
latestCharacterRead = Serial3.read(); //read next character in buffer
if( (latestCharacterRead == '\n') || (latestCharacterRead == '\r') ) //EOL character retrieved
{
//line line is now complete
line[numCharactersReceived] = STRING_TERMINATION_CHARACTER;
Serial3.print(F("\necho: "));
printStringStoredInArray(line); //echo user input
Serial3.print("\r");
if(numCharactersReceived >= USER_INPUT_BUFFER_SIZE) { Serial3.print(F("\nError: User typed too many characters")); }
else { USB_userInterface_executeUserInput(); }
numCharactersReceived = 0; //reset for next line
}
else //add (non-EOL) character to array
{
if(inputFlags && INPUT_FLAG_INSIDE_COMMENT)
{
if(latestCharacterRead == ')') { inputFlags &= ~(INPUT_FLAG_INSIDE_COMMENT); } //end of comment
}
else if(numCharactersReceived < (USER_INPUT_BUFFER_SIZE - 1))
{
//not presently inside a comment and input buffer not exceeded
if (latestCharacterRead == '(') { inputFlags |= INPUT_FLAG_INSIDE_COMMENT; } //start of comment //ignores all characters until ')'
else if(latestCharacterRead == ' ') { ; } //throw away whitespaces
else if( (latestCharacterRead >= 'a') && (latestCharacterRead <= 'z') )
{
line[numCharactersReceived++] = latestCharacterRead + ('A' - 'a'); //convert letters to uppercase
}
else {line[numCharactersReceived++] = latestCharacterRead; } //store everything else
}
}
}
}
/////////////////////////////////////////////////////////////////////////////////////////////
void setup() {
pinMode(LED_BUILTIN, OUTPUT);
pinMode(PB14, OUTPUT);
digitalWrite(PB14, LOW); // is this needed, or is this the default?
Serial3.begin(115200);
Serial3.println("Starting.");
bool ret = CANInit(CAN_1000KBPS, 2); // CAN_RX mapped to PB8, CAN_TX mapped to PB9
if (!ret) {
while(true) {
Serial3.println(ret);
Serial3.println("Failed to init! I'm now in an endless loop.");
}
}
}
void loop() {
// CAN_msg_t CAN_TX_msg;
// CAN_TX_msg.data[0] = 0x00;
// CAN_TX_msg.data[1] = 0x01;
// CAN_TX_msg.data[2] = 0x02;
// CAN_TX_msg.data[3] = 0x03;
// CAN_TX_msg.data[4] = 0x04;
// CAN_TX_msg.data[5] = 0x05;
// CAN_TX_msg.data[6] = 0x06;
// CAN_TX_msg.data[7] = 0x07;
// CAN_TX_msg.len = frameLength;
// unsigned long currentMillis = millis();
// if (currentMillis - previousMillis >= interval) {
// //if (0) {
// previousMillis = currentMillis;
// if ( ( counter % 2) == 0) {
// CAN_TX_msg.type = DATA_FRAME;
// if (CAN_TX_msg.len == 0) CAN_TX_msg.type = REMOTE_FRAME;
// CAN_TX_msg.format = EXTENDED_FORMAT;
// CAN_TX_msg.id = 0x32F103;
// } else {
// CAN_TX_msg.type = DATA_FRAME;
// if (CAN_TX_msg.len == 0) CAN_TX_msg.type = REMOTE_FRAME;
// CAN_TX_msg.format = STANDARD_FORMAT;
// CAN_TX_msg.id = 0x103;
// }
// CANSend(&CAN_TX_msg);
// frameLength++;
// if (frameLength == 9) frameLength = 0;
// counter++;
// }
// CANSend(&CAN_TX_msg);
CheckCANRxAndHandle();
USB_userInterface_handler();
}

9
CANBoard/src/main.h Normal file
View File

@@ -0,0 +1,9 @@
#ifndef main_h
#define main_h
#define USER_INPUT_BUFFER_SIZE 32
#define STRING_TERMINATION_CHARACTER 0
#define INPUT_FLAG_INSIDE_COMMENT 0x01
#endif

Binary file not shown.

View File

@@ -376,7 +376,7 @@
"sheets": [
[
"db3edc47-4828-4eea-922a-05c38d2f8b2c",
"Root"
""
]
],
"text_variables": {}

File diff suppressed because it is too large Load Diff

6
PCB.md
View File

@@ -16,8 +16,4 @@
- 8: ENABLE
## Enablement
The OEM enabement mechanism is not known.
A small modification can be made to allow ENABLE to be (in effect) a default pulled-down, on-if-high pin for ~2.8V V_ON.
Place a 800-1.2k resistor between the existing ENABLE pin line (for example, on one of the pads near the bottom right corner of the board) and pin 2 of the 752T SOIC-8. This pin 2@752T connects fairly directly into the center of the enable logic circuitry (it is the ON pin of the 752T, as well as one of the inhibitor pins keeping the LM25010 off).
Given voltage of the ENABLE pin V_ENABLE, when V_ENABLE >= V_BAT and V_BAT >= 10V, the BMS board will boot and run, per my Signal conversation with Tim on 10 Feb 2024 @ 4:22AM.