Hello , I am trying to communicate Raspberry Pi 5 with MCP2515 and STM32F412 using embassy. I am successful in receiving data from STM32F412 on Raspberry Pi but when I try to send something to STM from Pi computer I got a problem. I am using two tasks one for sending CAN frames to Pi computer and other for receiving frames from it. When I send something to STM32 it is receiving frame but task for sending frame halts.
Can configuration:
let mut can = Can::new(p.CAN1, p.PB8, p.PB9, Irqs);
// accept only id from main board ( with Raspberry Pi ).
can.modify_filters().enable_bank(0, Fifo::Fifo0, Mask32::frames_with_std_id(StandardId::new(0).unwrap(),StandardId::new(0x7FF).unwrap()));
can.set_automatic_wakeup(true);
can.modify_config()
.set_loopback(false) // Receive own frames
.set_silent(false)
.set_automatic_retransmit(false)
.set_bitrate(500_000);
can.enable().await;
can.flush_all().await;
let can_txrx: (embassy_stm32::can::CanTx<'_, CAN1>, embassy_stm32::can::CanRx<'_, CAN1>) = can.split();
Clock configuration ( I am using 25 Mhz crystal )
let mut config = Config::default();
config.rcc.hse = Some(Hse{
freq: Hertz(25_000_000),
mode: HseMode::Oscillator
});
config.rcc.pll_src = PllSource::HSE;
config.rcc.sys = Sysclk::PLL1_P;
config.rcc.pll = Some(Pll{
prediv:PllPreDiv::DIV25,
mul:PllMul::MUL192,
divp:Some(PllPDiv::DIV4),
divr:Some(PllRDiv::DIV2),
divq:Some(PllQDiv::DIV2)
});
config.rcc.ahb_pre = AHBPrescaler::DIV1;
config.rcc.apb1_pre = APBPrescaler::DIV1;
config.rcc.apb2_pre = APBPrescaler::DIV1;
let p = embassy_stm32::init(config);
Transmit and recive tasks ( Scenic is for transmit and Espace is for reciving )
#[embassy_executor::task]
async fn espace_task(mut espace:Espace<'static>)
{
loop {
info!("Espace!");
espace.run().await;
}
}
#[embassy_executor::task]
async fn scenic_task(mut scenic:Scenic<'static>)
{
loop {
info!("Scenic!");
scenic.run().await;
}
}
Espace task:
#![no_main]
#![no_std]
use core::cell::RefCell;
use core::sync::atomic::AtomicBool;
use cortex_m::singleton;
use defmt::{info, unwrap};
use embassy_stm32::peripherals::CAN1;
use embassy_stm32::spi::{RxDma,TxDma};
use embassy_stm32::{peripherals, Peripheral};
use embassy_stm32::{i2c::I2c, mode::Async, peripherals::I2C3};
use embassy_sync::blocking_mutex::{raw::ThreadModeRawMutex, Mutex};
use embassy_sync::channel::Channel;
use mpu6050::Mpu6050;
use crate::module::mag::Mag;
use crate::module::registers::IMUData;
use crate::module::shared::{AUXDATA, FUSIONDATA, MOTORDATA, SERVODATA};
use crate::module::shared::IMUDATA;
use crate::module::shared::PIDSERVODATA;
use crate::tasks::megane::IMUCHANNEL;
use embassy_stm32::can::filter::Mask32;
use embassy_stm32::can::{
Can, CanRx, Fifo, Frame, Rx0InterruptHandler, Rx1InterruptHandler, SceInterruptHandler, StandardId, TxInterruptHandler
};
use super::scenic::{CanFrame, SCENIC_TRUNK};
pub static MEGANE_UPDATE:AtomicBool = AtomicBool::new(false);
pub static LAGUNA_UPDATE:AtomicBool = AtomicBool::new(false);
pub static LAGUNA_MOTOR_UPDATE:AtomicBool = AtomicBool::new(false);
pub static LAGUNA_SERVO_UPDATE:AtomicBool = AtomicBool::new(false);
pub static CLIO_UPDATE:AtomicBool = AtomicBool::new(false);
/// a task for reading data from CAN
pub struct Espace<'a>
{
can:CanRx<'a,CAN1>
}
impl<'a> Espace<'a> {
pub fn new(can:CanRx<'a,CAN1>) ->Self
{
Espace{
can
}
}
// recive task, add read from registers options ( first bit in id byte would indicate write/read ( 0 for read and 1 for write ))
pub async fn run(&mut self)
{
let input_data = self.can.read().await;
info!("Espace got data!");
if input_data.is_ok()
{
let frame = input_data.unwrap().frame;
let data = frame.data();
// read offset
if data.len() >= 3
{
let mut id:u8 = data[0];
// check if last bit is set to 1
let writing = ( id & 0x7f ) == 0;
id = id & !0x7f;
let mut offset:u16 = 0;
offset = data[1] as u16 | ( (data[2] as u16) << 8 );
let remaing_data = &data[3..];
info!("Offset: {}",offset);
match id {
0 =>
{
let imu = IMUDATA.lock().await;
if writing
{
info!("Wiriting to IMU!");
imu.borrow_mut().data[offset as usize..offset as usize + remaing_data.len() as usize].copy_from_slice(remaing_data);
}
else {
let mut frame: CanFrame = CanFrame::new(255,imu.borrow_mut().data.len() as u8);
info!("Sending from IMU!");
let len = imu.borrow().data.len();
frame.data[..len].copy_from_slice(&imu.borrow().data);
SCENIC_TRUNK.send(frame).await;
}
}
1 =>
{
let aux = AUXDATA.lock().await;
if writing
{
info!("Wiriting to AUX!");
aux.borrow_mut().data[offset as usize..offset as usize + remaing_data.len() as usize].copy_from_slice(remaing_data);
}
else {
info!("Sending to AUX!");
let mut frame: CanFrame = CanFrame::new(254,aux.borrow_mut().data.len() as u8);
frame.data[..aux.borrow_mut().data.len()].copy_from_slice(&aux.borrow_mut().data);
SCENIC_TRUNK.send(frame).await;
}
}
2 =>
{
let pid = PIDSERVODATA.lock().await;
if writing
{
info!("Wiriting to PID!");
pid.borrow_mut().data[offset as usize..offset as usize + remaing_data.len() as usize].copy_from_slice(remaing_data);
}
else {
info!("Sending from IMU!");
let mut frame: CanFrame = CanFrame::new(253,pid.borrow_mut().data.len() as u8);
frame.data[..pid.borrow_mut().data.len()].copy_from_slice(&pid.borrow_mut().data);
SCENIC_TRUNK.send(frame).await;
}
}
3 =>
{
let servo = SERVODATA.lock().await;
if writing
{
info!("Wiriting to Servo!");
servo.borrow_mut().data[offset as usize..offset as usize + remaing_data.len() as usize].copy_from_slice(remaing_data);
}
else {
info!("Sending from Servo!");
let mut frame: CanFrame = CanFrame::new(252,servo.borrow_mut().data.len() as u8);
frame.data[..servo.borrow_mut().data.len()].copy_from_slice(&servo.borrow_mut().data);
SCENIC_TRUNK.send(frame).await;
}
}
4 =>
{
let motor = MOTORDATA.lock().await;
if writing
{
info!("Wiriting to Motor!");
motor.borrow_mut().data[offset as usize..offset as usize + remaing_data.len() as usize].copy_from_slice(remaing_data);
}
else {
info!("Sending from Motor!");
let mut frame: CanFrame = CanFrame::new(251,motor.borrow_mut().data.len() as u8);
frame.data[..motor.borrow_mut().data.len()].copy_from_slice(&motor.borrow_mut().data);
SCENIC_TRUNK.send(frame).await;
}
}
5 =>
{
let fusion = FUSIONDATA.lock().await;
if writing
{
info!("Wiriting to Fusion!");
fusion.borrow_mut().data[offset as usize..offset as usize + remaing_data.len() as usize].copy_from_slice(remaing_data);
}
else {
info!("Sending from Fusion!");
let mut frame: CanFrame = CanFrame::new(250,fusion.borrow_mut().data.len() as u8);
frame.data[..fusion.borrow_mut().data.len()].copy_from_slice(&fusion.borrow_mut().data);
SCENIC_TRUNK.send(frame).await;
}
}
_=>{}
}
}
}
}
}
Scenic task:
#![no_main]
#![no_std]
use core::borrow::Borrow;
use core::cell::RefCell;
use cortex_m::singleton;
use defmt::unwrap;
use embassy_stm32::peripherals::CAN1;
use embassy_stm32::spi::{RxDma,TxDma};
use embassy_stm32::{peripherals, Peripheral};
use embassy_stm32::{i2c::I2c, mode::Async, peripherals::I2C3};
use embassy_sync::blocking_mutex::{raw::ThreadModeRawMutex, Mutex};
use embassy_sync::channel::Channel;
use mpu6050::Mpu6050;
use usbd_hid::descriptor::generator_prelude::Serialize;
use crate::module::mag::Mag;
use crate::module::shared::AUXDATA;
use crate::module::shared::IMUDATA;
use crate::module::shared::PIDSERVODATA;
use crate::tasks::megane::IMUCHANNEL;
use embassy_stm32::can::filter::Mask32;
use embassy_stm32::can::{
Can, CanTx, Fifo, Frame, Rx0InterruptHandler, Rx1InterruptHandler, SceInterruptHandler, StandardId, TxInterruptHandler
};
pub trait Framed
{
fn serialize(&self)->&[u8];
fn get_id(self)->u8;
}
pub struct CanFrame
{
pub data:[u8;65],
pub size:u8,
pub id:u8,
pub target_id:u16,
}
impl CanFrame {
pub fn new(id:u8,size:u8) -> Self
{
CanFrame{
id,
size,
data:[0;65],
target_id:1
}
}
}
pub static SCENIC_TRUNK:Channel<ThreadModeRawMutex,CanFrame,10> = Channel::new();
/// a task for reading data from CAN
pub struct Scenic<'a>
{
can:CanTx<'a,CAN1>
}
impl<'a> Scenic<'a> {
pub fn new(can:CanTx<'a,CAN1>) ->Self
{
Scenic{
can
}
}
// recive task
pub async fn run(&mut self)
{
// wait for incoming frame
let frame = SCENIC_TRUNK.receive().await;
if frame.size == 0
{
return ;
}
let data = &frame.data[..(frame.size) as usize];
let id = frame.id;
let mut offset:u16 = 0;
for chunk in data.chunks(5)
{
let mut msg:[u8;8]=[0;8];
msg[0] = id;
// msg[1] = ( offset>>8 & 0xFF ) as u8;
// msg[2] = ( offset & 0xFF ) as u8;
msg[1..3].clone_from_slice(&offset.to_le_bytes());
msg[3..(3+chunk.len())].clone_from_slice(chunk);
let frame = Frame::new_data(unwrap!(StandardId::new(frame.target_id)), &msg[..(3+chunk.len())]).unwrap();
self.can.write(&frame).await;
offset += chunk.len() as u16;
}
}
}
I am rather fresh in embedded Rust and I have used to program such thinks in C so I am open for suggestions.