Comments (9)
What clock crystal were the bit timings calculated with?
int result = ComputeCANTimings(HAL_RCC_GetPCLK1Freq(), target_bitrate, &timings);
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) {
Serial.print("target_bitrate=");
Serial.println(target_bitrate);
Serial.print("peripheral_clock_rate=");
Serial.println(peripheral_clock_rate);
Serial.print("timings.baud_rate_prescaler=");
Serial.println(out_timings->baud_rate_prescaler);
Serial.print("timings.time_segment_1=");
Serial.println(out_timings->time_segment_1);
Serial.print("timings.time_segment_2=");
Serial.println(out_timings->time_segment_2);
Serial.print("timings.resynchronization_jump_width=");
Serial.println(out_timings->resynchronization_jump_width);
}
return 0;
}
from arduino-stm32-can.
hi, thanks for the code.
We are monitoring the CANTX/CANRX lines and we can see messages coming in on CANRX but there is absolutely no activity on CANTX. We are expecting the STM32 to atleast ACK the incoming CAN message...
Weird thing is, the message does arrive in the code but there is no ACK so the sender just keeps on sending it...
from arduino-stm32-can.
Can you configure the sender and receiver with two stm32s and see the difference?
from arduino-stm32-can.
We found the problem. Turns out the HSE crystal on our PCB was not enabled in software thus we were using the internal RC circuit as clock.
This works fine if you have two of the same STM32s on the same bus, but once you add a CAN bus device with a different clock (like our STM32H7 boards) the communication starts getting weird.
We managed to use some code generated by STM32CubeIde to get our HSE working and setup and now we are happily sharing a CAN bus with multiple STM32F446s and multiple STM32H7s. Thanks for your help and thanks for your amazing work on this library!
from arduino-stm32-can.
We found the problem. Turns out the HSE crystal on our PCB was not enabled in software thus we were using the internal RC circuit as clock.
This works fine if you have two of the same STM32s on the same bus, but once you add a CAN bus device with a different clock (like our STM32H7 boards) the communication starts getting weird.
We managed to use some code generated by STM32CubeIde to get our HSE working and setup and now we are happily sharing a CAN bus with multiple STM32F446s and multiple STM32H7s. Thanks for your help and thanks for your amazing work on this library!
Hey! I am glad you found a solution to your problem. I am also using this library and using the same MCU (stm32f446) and external crystal. Could you share your solution or code? My setup is working but I am getting a lot of transmission errors. Thank you!
from arduino-stm32-can.
The stm32f446 sample is for STM32F4 that operates with the following clocks.
F_CPU=180000000
HAL_RCC_GetPCLK1Freq=45000000
I only have this clock board.
It will not work with any other clock.
from arduino-stm32-can.
Can you share your STM32H7 CAN transmit/receive source code?
from arduino-stm32-can.
The stm32f446 sample is for STM32F4 that operates with the following clocks.
F_CPU=180000000 HAL_RCC_GetPCLK1Freq=45000000
I only have this clock board.
It will not work with any other clock.
Ok thank you. It is working fine now and also got it working for stm32f103c. Can you tell me is CAN msg autoretransmission enabled or disabled in your code? Also how could we set those bits by ourselves?
from arduino-stm32-can.
Can you tell me is CAN msg autoretransmission enabled or disabled in your code?
https://github.com/nopnop2002/Arduino-STM32-CAN/blob/master/stm32f103/stm32f103.ino#L327
https://github.com/nopnop2002/Arduino-STM32-CAN/blob/master/stm32f103/stm32f103.ino#L328
from arduino-stm32-can.
Related Issues (20)
- the lib didn't work well HOT 4
- Send Fail HOT 16
- Canard HOT 1
- Possible to read but can't send data. HOT 28
- Raspberry Pi wiring example issue HOT 1
- STM32F103C8T6 hangs on CANInit(CAN_1000KBPS, 2) HOT 3
- STM32F103 gets stuck inside while (!(CAN1->MSR & 0x1UL)); HOT 26
- Send Fail on STM32F407VE HOT 15
- how is Serial and CAN being used simultaneously in STM32F103? HOT 3
- STM32F413ZH NUCLEO-F413ZH HOT 13
- CAN on STM32G4 series HOT 1
- Discuss: other ways to clear mailbox? HOT 1
- Mistake in Line 277 HOT 5
- STM32F042F6P6TR HOT 1
- feature request: support multiple transmit mailboxes HOT 12
- BARTH STG-850 Support HOT 5
- Unable to communicate STM32f103 vs ESP32 via CAN BUS HOT 2
- Sending data issue HOT 9
- dlc bigger than 8 HOT 7
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from arduino-stm32-can.