cancel
Showing results for 
Search instead for 
Did you mean: 

CAN bus able to read but not send message

Asperagabriel
Associate

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:

Asperagabriel_0-1752285434853.pngAsperagabriel_1-1752285447908.pngAsperagabriel_2-1752285464498.png

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. 




2 REPLIES 2
Karl Yamashita
Principal

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?

I was told that if a devices starts to smoke, put the smoke back in. I guess I never got all the smoke because the device never worked afterwards.
Don't worry, I won't byte.
TimerCallback tutorial! | UART and DMA Idle tutorial!

If you find my solution useful, please click the Accept as Solution so others see the solution.

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.