2025-07-11 2:41 PM - edited 2025-07-11 7:03 PM
Hello,
I have a STM32F407G-DISC1 (a blue one, do not know if that matters), that I am using to prototype a system where I communicate via CAN bus to a boost recuperation machine, however I am not able to see my messages on the osciloscope, I am able to receive the messages from the machine, which clearly is sending messages when I check with the scope and the readings are coherent.
// Inclui os cabeçalhos necessários
#include "app.h"
#include "CAN.h"
#include "DBC.h"
// Define macros para verificar o estado da ignição e do pedal de freio
#define IgnOn HAL_GPIO_ReadPin(GPIOE, IgnSwt_Pin) == GPIO_PIN_SET // Ign ligado
#define Braking HAL_GPIO_ReadPin(GPIOA, BrkState_Pin) == GPIO_PIN_RESET // Freio pressionado (ativo em nível baixo)
//extern ADC_HandleTypeDef hadc1; // Handler do ADC usado para ler o pedal
extern CAN_HandleTypeDef hcan1; // Handler do barramento CAN1
extern CAN_HandleTypeDef hcan2; // Handler do barramento CAN2 (comentado)
extern uint8_t Pt_Edrv_Des_1[8]; // Buffer da mensagem CAN "Pt_Edrv_Des_1"
extern uint8_t Eem_Edrv_Lim_1[8]; // Buffer da mensagem CAN "Eem_Edrv_Lim_1"
CAN_TxHeaderTypeDef TxHeader[4]; // Cabeçalhos de transmissão CAN
int msgCount; // Contador de mensagens CAN
// Flags de envio das mensagens (modo B)
extern uint8_t Pt_Edrv_Des_1_flag;
extern uint8_t Eem_Edrv_Lim_1_flag;
// Flags de envio alternativo (modo A, comentado)
extern uint8_t Pt_Edrv_Des_1_flagA;
extern uint8_t Eem_Edrv_Lim_1_flagA;
uint32_t TxMailbox[2]; // Mailboxes usados para envio CAN
// Sinais CAN utilizados no sistema (definidos em `DBC.c`)
extern volatile CanSignal Edrv_uAct, Pt_tqDesEdrv, Pt_stIgnSwt, Edrv_stOperModAct;
extern volatile CanSignal Edrv_tqMaxAvl, Pt_stOperModDesEdrv, Eem_uMaxEdrv, Eem_uMinEdrv;
extern volatile CanSignal Edrv_iAct, Pt_nrAlvCntrDes, Edrv_stRunAct;
uint16_t PPS; // Valor lido do pedal (ADC)
volatile uint8_t rtd; // Flag para indicar se está pronto para dirigir (RTD)
volatile state TSstate; // Estado atual da máquina de estados (STANDBY, RTD, etc.)
// Função utilitária para mapear um valor de uma faixa para outra
long map(long x, long in_min, long in_max, long out_min, long out_max)
{
return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}
// Função de setup do sistema (chamada uma vez no início)
void setup()
{
TSstate = STANDBY; // Define estado inicial como STANDBY
CAN_init(); // Inicializa o barramento CAN
}
// Função que lê sinais e atualiza o estado geral do sistema
void read()
{
// HAL_ADC_Start(&hadc1); // Inicia conversão ADC
// HAL_ADC_PollForConversion(&hadc1, 10); // Aguarda conversão
// PPS = HAL_ADC_GetValue(&hadc1); // Lê valor do pedal
// Atualiza valor da ignição
// if(IgnOn)
// Pt_stIgnSwt.data = 0x4;
// else
// Pt_stIgnSwt.data = 0;
Pt_stIgnSwt.data = 0x4;
// Verificações de falha
if(Edrv_uAct.data > Eem_uMaxEdrv.data || // Tensão acima do máximo
Edrv_uAct.data < Eem_uMinEdrv.data || // Tensão abaixo do mínimo
Edrv_iAct.data > 87.5 || // Corrente acima do limite
Edrv_stRunAct.data == 0x7) // Estado de falha do inversor
TSstate = FAILURE; // Entra em modo falha
else if(Edrv_stRunAct.data >= 0x3) // Estado de desligamento
TSstate = SHUTDOWN;
}
// Função principal que roda continuamente
void loop()
{
read(); // Atualiza os sinais
// Máquina de estados do sistema
// switch(TSstate)
// {
// case STANDBY:
// // Verifica se ignição está ligada e inversor em idle
// if(Pt_stIgnSwt.data == 0x4 && Edrv_stOperModAct.data == 0)
// TSstate = NOT_RTD;
// break;
//
// case NOT_RTD:
// // Condição para permitir entrada no modo PRE_RTD
// if((Edrv_stOperModAct.data == 0x0) && (IgnOn && Braking) && Edrv_uAct.data >= Eem_uMinEdrv.data)
// TSstate = PRE_RTD;
// break;
//
// case PRE_RTD:
// // Solicita modo operacional e torque mínimo
// Pt_stOperModDesEdrv.data = 0x1;
// Pt_tqDesEdrv.data = 0.01;
//
// // Verifica se entrou em modo RTD
// if(Edrv_stOperModAct.data == 0x1)
// TSstate = RTD;
// break;
//
// case RTD:
// // Lógica para controle de torque
// if(Braking)
// {
// Pt_tqDesEdrv.data = 0; // Torque zero ao frear
// }
// else
// {
// PPS = map(PPS, 0, 4095, 0, 100); // Mapeia valor do pedal para %
// Pt_tqDesEdrv.data = (PPS) * (Edrv_tqMaxAvl.data / 100); // Torque proporcional
// }
// break;
//
// case FAILURE:
// // Estado de falha — precisa ser escrita uma rotina dde falha
// break;
//
// case SHUTDOWN:
// // Estado de desligamento — precisa ser escrita uma rotina dde falha
// break;
//
// default:
// TSstate = STANDBY; // Define estado inicial como STANDBY
// break;
// }
// Se há mailbox CAN livre, envia mensagens
// if ((HAL_CAN_GetTxMailboxesFreeLevel(&hcan2) > 0) || (HAL_CAN_GetTxMailboxesFreeLevel(&hcan1)))
// {
// Envia mensagem Eem_Edrv_Lim_1 se necessário
if(Eem_Edrv_Lim_1_flag)
{
clearMessage(Eem_Edrv_Lim_1); // Limpa payload
Eem_Edrv_Lim_1_send(); // Atualiza conteúdo da mensagem
if(HAL_CAN_AddTxMessage(&hcan1, &TxHeader[1], Eem_Edrv_Lim_1, &TxMailbox[0]) != HAL_OK)
msgCount++; // Se falhou, incrementa erro
else
msgCount--; // Sucesso
if(HAL_CAN_AddTxMessage(&hcan2, &TxHeader[3], Eem_Edrv_Lim_1, &TxMailbox[0]) != HAL_OK)
msgCount++; // Se falhou, incrementa erro
else
msgCount--; // Sucesso
Eem_Edrv_Lim_1_flag = 0; // Limpa flag
}
// Envia mensagem Pt_Edrv_Des_1 se necessário
if(Pt_Edrv_Des_1_flag)
{
clearMessage(Pt_Edrv_Des_1); // Limpa payload
Pt_Edrv_Des_1_send(); // Atualiza conteúdo da mensagem
if(HAL_CAN_AddTxMessage(&hcan1, &TxHeader[0], Pt_Edrv_Des_1, &TxMailbox[1]) != HAL_OK)
{
msgCount++; // Se falhou, erro
}
else
{
Pt_nrAlvCntrDes.data++; // Incrementa contador de vida
if(Pt_nrAlvCntrDes.data > 15) // Limita em 4 bits
Pt_nrAlvCntrDes.data = 0;
msgCount--; // Sucesso
}
if(HAL_CAN_AddTxMessage(&hcan2, &TxHeader[2], Pt_Edrv_Des_1, &TxMailbox[1]) != HAL_OK)
{
msgCount++; // Se falhou, erro
}
else
{
Pt_nrAlvCntrDes.data++; // Incrementa contador de vida
if(Pt_nrAlvCntrDes.data > 15) // Limita em 4 bits
Pt_nrAlvCntrDes.data = 0;
msgCount--; // Sucesso
}
Pt_Edrv_Des_1_flag = 0; // Limpa flag
}
}
//}
/*
* CAN.c
*
* Created on: Jun 7, 2023
* Author: gabri
*/
// Inclusão dos cabeçalhos necessários
#include "CAN.h"
#include "main.h"
// Definição dos identificadores CAN padrão (IDs das mensagens)
#define Eem_Edrv_Lim_1_ID 0xA5
#define Pt_Edrv_Des_1_ID 0xA6
// Declaração de handle externo para o periférico CAN1
extern CAN_HandleTypeDef hcan1;
extern CAN_HandleTypeDef hcan2; // CAN2 está comentado, não será utilizado
// Headers para transmissão CAN, definidos externamente
extern CAN_TxHeaderTypeDef TxHeader[4];
// Header de recepção CAN
CAN_RxHeaderTypeDef RxHeader;
// Flags de controle que indicam quando cada mensagem deve ser enviada
uint8_t Pt_Edrv_Des_1_flag = 0;
uint8_t Eem_Edrv_Lim_1_flag = 0;
// Buffer para armazenar os dados recebidos via CAN
uint8_t RxData[8];
// Variável de teste usada para verificar qual CAN recebeu mensagem
uint8_t teste;
// Função para inicializar o CAN e configurar timers e filtros
void CAN_init(void)
{
// Configuração inicial do CAN1 (poderia ser modo normal, está comentado)
//hcan1.Init.Mode = CAN_MODE_NORMAL;
// Inicializa CAN1 e checa se ocorreu erro
if (HAL_CAN_Init(&hcan1) != HAL_OK)
{
Error_Handler(); // Em caso de erro na inicialização do CAN1
}
// Inicialização do CAN2 está comentada
// Configuração do primeiro header de transmissão (ID Pt_Edrv_Des_1_ID)
TxHeader[0].DLC = 7; // Tamanho dos dados: 7 bytes
TxHeader[0].ExtId = 0; // Não utilizado em modo ID padrão
TxHeader[0].IDE = CAN_ID_STD; // Usar ID padrão (11 bits)
TxHeader[0].RTR = CAN_RTR_DATA; // Frame de dados (não remoto)
TxHeader[0].StdId = Pt_Edrv_Des_1_ID; // ID da mensagem
TxHeader[0].TransmitGlobalTime = DISABLE; // Desativa carimbo de tempo
// Configuração do segundo header de transmissão (ID Eem_Edrv_Lim_1_ID)
TxHeader[1].DLC = 8;
TxHeader[1].ExtId = 0;
TxHeader[1].IDE = CAN_ID_STD;
TxHeader[1].RTR = CAN_RTR_DATA;
TxHeader[1].StdId = Eem_Edrv_Lim_1_ID;
TxHeader[1].TransmitGlobalTime = DISABLE;
TxHeader[2].DLC = 7; // Tamanho dos dados: 7 bytes
TxHeader[2].ExtId = 0; // Não utilizado em modo ID padrão
TxHeader[2].IDE = CAN_ID_STD; // Usar ID padrão (11 bits)
TxHeader[2].RTR = CAN_RTR_DATA; // Frame de dados (não remoto)
TxHeader[2].StdId = 0xA3; // ID da mensagem
TxHeader[2].TransmitGlobalTime = DISABLE; // Desativa carimbo de tempo
// Configuração do segundo header de transmissão (ID Eem_Edrv_Lim_1_ID)
TxHeader[3].DLC = 8;
TxHeader[3].ExtId = 0;
TxHeader[3].IDE = CAN_ID_STD;
TxHeader[3].RTR = CAN_RTR_DATA;
TxHeader[3].StdId = 0xA4;
TxHeader[3].TransmitGlobalTime = DISABLE;
// Configuração do filtro CAN para aceitar apenas IDs 0xA3 e 0xA4
CAN_FilterTypeDef filter = {0};
filter.FilterBank = 12; // Banco de filtro 12
filter.FilterMode = CAN_FILTERMODE_IDLIST; // Modo lista de IDs
filter.FilterScale = CAN_FILTERSCALE_16BIT; // Escala de 16 bits
filter.FilterFIFOAssignment = CAN_FILTER_FIFO0; // FIFO 0
filter.FilterActivation = ENABLE; // Ativa o filtro
filter.SlaveStartFilterBank = 14; // Para dual-CAN (não usado aqui)
// Define os dois IDs aceitos pelo filtro (convertidos para formato CAN)
filter.FilterIdHigh = (0xA3 << 5); // Shift para 16 bits
filter.FilterIdLow = (0xA4 << 5);
// Configuração do filtro CAN para aceitar apenas IDs 0xA3 e 0xA4
CAN_FilterTypeDef sfilter = {0};
sfilter.FilterBank = 15; // Banco de filtro 12
sfilter.FilterMode = CAN_FILTERMODE_IDLIST; // Modo lista de IDs
sfilter.FilterScale = CAN_FILTERSCALE_16BIT; // Escala de 16 bits
sfilter.FilterFIFOAssignment = CAN_FILTER_FIFO0; // FIFO 0
sfilter.FilterActivation = ENABLE; // Ativa o filtro
sfilter.SlaveStartFilterBank = 14; // Para dual-CAN (não usado aqui)
// Define os dois IDs aceitos pelo filtro (convertidos para formato CAN)
sfilter.FilterIdHigh = (0xA3 << 5); // Shift para 16 bits
sfilter.FilterIdLow = (0xA4 << 5);
// Configura o filtro no CAN1 e verifica erro
if (HAL_CAN_ConfigFilter(&hcan1, &filter) != HAL_OK)
{
Error_Handler(); // Erro na configuração do filtro
}
// Ativa interrupções de mensagens recebidas no FIFO0 do CAN1
if (HAL_CAN_ActivateNotification(&hcan1, CAN_IT_RX_FIFO0_MSG_PENDING) != HAL_OK)
{
Error_Handler();
}
if (HAL_CAN_ConfigFilter(&hcan2, &sfilter) != HAL_OK)
{
Error_Handler(); // Erro na configuração do filtro
}
// Ativa interrupções de mensagens recebidas no FIFO0 do CAN1
if (HAL_CAN_ActivateNotification(&hcan2, CAN_IT_RX_FIFO0_MSG_PENDING) != HAL_OK)
{
Error_Handler();
}
// Inicia o periférico CAN1
if (HAL_CAN_Start(&hcan1) != HAL_OK)
{
Error_Handler();
}
if (HAL_CAN_Start(&hcan2) != HAL_OK)
{
Error_Handler();
}
// Configuração e inicialização do Timer 4 (TIM4) para gerar interrupções periódicas
NVIC_EnableIRQ(TIM4_IRQn); // Habilita a interrupção do TIM4
TIM4->PSC = 16799; // Prescaler: 1ms com clock de 168 MHz
TIM4->ARR = 1000; // Auto-reload: 10000 ms / 10 segundos
TIM4->DIER |= TIM_DIER_UIE; // Habilita interrupção por update
TIM4->CR1 |= TIM_CR1_CEN; // Liga o timer
}
// Callback chamado quando mensagem CAN é recebida no FIFO0
void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan)
{
// Lê a mensagem recebida do FIFO0 para RxHeader e RxData
if (HAL_CAN_GetRxMessage(hcan, CAN_RX_FIFO0, &RxHeader, RxData) != HAL_OK)
{
Error_Handler(); // Em caso de erro na leitura da mensagem
}
else
teste++;
// Processa a mensagem recebida com base no ID e dados
processCanMessage(RxData, RxHeader.StdId);
}
// Rotina de tratamento da interrupção do Timer TIM4
void TIM4_IRQHandler(void)
{
if (TIM4->SR & TIM_SR_UIF) // Verifica flag de atualização (overflow)
{
TIM4->SR &= ~TIM_SR_UIF; // Limpa a flag de atualização
Pt_Edrv_Des_1_flag = 1; // Sinaliza que deve enviar mensagem 1
Eem_Edrv_Lim_1_flag = 1; // Sinaliza que deve enviar mensagem 2
}
NVIC_ClearPendingIRQ(TIM4_IRQn); // Limpa interrupções pendentes do NVIC
}
// Função auxiliar para limpar (zerar) um buffer de mensagem CAN de 8 bytes
void clearMessage(uint8_t* message)
{
for (int i = 0; i < 8; i++) message[i] = 0; // Zera cada byte do buffer
}
/*
* CAN.H
*
* Created on: Jun 7, 2023
* Author: gabri
*/
#ifndef LIB_CAN_H_
#define LIB_CAN_H_
#include "main.h"
#include "DBC.h"
typedef struct can_signal{
float data;
int bit_lenght;
int data_bin[100];
float resolution;
int offset;
}can_signal;
void CAN_init();
void Pt_Veh_1_send();
void Eem_Edrv_Lim_1_send();
void Pt_Edrv_Des_1_send();
void clearMessage(uint8_t* message);
#endif /* LIB_CAN_H_ */
Sorry for the portuguese comments and for the polluted parts of the code that does not impact the issue.
Edit: corrected the board name also included the ioc file attached.
Edit 2:
I tried these three modules, the first two were able to read the motor, the third one wasn't, all of them worked fine in Loopback. All three were wired up the same way TX and RX to the the respective TX or RX of the STM CAN1 or CAN2 TX and RX and CANH and CANL were wired to the the motor or other transceiver modules (that is why CAN2 is active) respective CANH and CANL. The motor itself does not have the 120ohm terminator, but I am able to read it via osciloscope.
2025-07-11 4:36 PM
You have not shown how the hardware is set up.
What are the 2 CAN busses connected to? They both don't send CAN messages?
Are there terminating resistors?
2025-07-11 6:55 PM
Sorry, I'll reedit the question addinthe what the hardware layout should look like, but I am using CAN transceiver modules that are terminated by resistor, the second CAN was used for trying to communicate with each other, no success. The tests where I could read were just a transceiver and the BRM.