2 votes

STM32 CAN loop back mode

Je commence une utilisation basique des pilotes HAL pour le mode loop back du périphérique CAN dans le MCU STM32F103xx. D'après le manuel d'utilisation de la MCU, lorsque la transmission est complètement terminée et que les données deviennent disponibles sur le bus CAN, les bits TME, RQCP et TXOK du registre CAN_TSR sont activés par le matériel, montrant que la boîte aux lettres correspondante est devenue vide et que la transmission a été effectuée avec succès.

Lorsque je débogue le programme suivant, aucun des changements mentionnés ne se produit dans le registre CAN_TSR. Je vois seulement que le bit TME est activé, ce qui signifie qu'une boîte aux lettres est prévue pour la transmission mais n'est jamais transmise.

Ce morceau de mon code provoque une boucle infinitive dans le programme :

while(HAL_CAN_IsTxMessagePending(&hcan, TxMailbox));

Pourriez-vous m'expliquer quel est mon problème et ce que je dois faire ? Merci pour vos idées.

Voici le code complet :

#include "main.h"
CAN_HandleTypeDef hcan;

void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_CAN_Init(void);

/* USER CODE BEGIN PFP */
void Can_TX(void);
/* USER CODE END PFP */

int main(void)
{
  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();
  /* Configure the system clock */
  SystemClock_Config();
  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_CAN_Init();

  /* USER CODE BEGIN 2 */
  LCD1602_Begin4BIT(RS_GPIO_Port, RS_Pin, E_Pin, D4_GPIO_Port, D4_Pin, D5_Pin, D6_Pin, D7_Pin);
  LCD1602_print("Sending...");
  Can_TX();
  /* USER CODE END 2 */

  /* Infinite loop */
  while (1)
  {
    for (int i = 0; i <= 1000; i++);
  }
}

void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != HAL_OK)
  {
    Error_Handler();
  }
}

static void MX_CAN_Init(void)
{
  hcan.Instance = CAN1;
  hcan.Init.Prescaler = 1;
  hcan.Init.Mode = CAN_MODE_LOOPBACK;
  hcan.Init.SyncJumpWidth = CAN_SJW_1TQ;
  hcan.Init.TimeSeg1 = CAN_BS1_13TQ;
  hcan.Init.TimeSeg2 = CAN_BS2_2TQ;
  hcan.Init.TimeTriggeredMode = DISABLE;
  hcan.Init.AutoBusOff = DISABLE;
  hcan.Init.AutoWakeUp = DISABLE;
  hcan.Init.AutoRetransmission = ENABLE;
  hcan.Init.ReceiveFifoLocked = DISABLE;
  hcan.Init.TransmitFifoPriority = DISABLE;
  if (HAL_CAN_Init(&hcan) != HAL_OK)
  {
    Error_Handler();
  }
}

static void MX_GPIO_Init(void)
{
  GPIO_InitTypeDef GPIO_InitStruct = {0};
  __HAL_RCC_GPIOA_CLK_ENABLE();
  HAL_GPIO_WritePin(GPIOA, RS_Pin|E_Pin|D4_Pin|D5_Pin|D6_Pin|D7_Pin, GPIO_PIN_RESET);
  GPIO_InitStruct.Pin = RS_Pin|E_Pin|D4_Pin|D5_Pin|D6_Pin|D7_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}

void Can_TX(void)
{
  CAN_TxHeaderTypeDef TxHeader;
  uint8_t our_message[5] = {'H','E','L','L','O'};
  uint32_t TxMailbox;
  TxHeader.DLC = 1;
  TxHeader.StdId = 0x65D;
  TxHeader.IDE = CAN_ID_STD;
  TxHeader.RTR = CAN_RTR_DATA;
  HAL_CAN_AddTxMessage(&hcan, &TxHeader, our_message, &TxMailbox);
  if(HAL_CAN_AddTxMessage(&hcan, &TxHeader, our_message, &TxMailbox) != HAL_OK)
  {
    Error_Handler();
  }
  while(HAL_CAN_IsTxMessagePending(&hcan, TxMailbox));
  LCD1602_print("Message is sent");
}

void Error_Handler(void) { }

6voto

thomashamain Points 31

Je peux avoir des informations supplémentaires qui pourraient être utiles, sur la façon dont le réglage correct des timings de bits a résolu mon problème et a fait en sorte que mon message tx quitte la boîte aux lettres sans erreur.

Je voulais tester mon périphérique CAN avec la fonction loopback mais le message est resté bloqué dans la boîte aux lettres.

En lisant attentivement la documentation, j'ai d'abord constaté que j'avais oublié HAL_CAN_Start() como Proposition de por Coup de pouce et en effet, le drapeau INRQ était toujours activé. (Il est activé par HAL_CAN_Init .)

Après cette modification, je ne voyais aucun message du côté de la réception et je n'étais pas sûr que le message avait été correctement envoyé. En cherchant la cause, j'ai noté que RQCPx a été mis à 1, ce qui signifie que, indépendamment du succès ou de l'erreur, la demande de transmission a été achevée, TXOKx à 0 et TERRx à 1, ce qui signifie qu'il y a eu une erreur de transmission. Le site LEC (dernier code d'erreur) bits de CAN_ESR (registres d'état d'erreur) ont été réglés sur 101, ou, selon la documentation, sur une erreur dominante.

Je n'ai pas exactement compris ce que cela signifie, une clarification serait la bienvenue pour mieux comprendre comment faire pour que le message quitte correctement la boîte aux lettres, mais en tombant sur ce fil de discussion de la communauté st J'ai compris que l'utilisation de paramètres de synchronisation aléatoires ne donnerait pas de bons résultats. (Cela semble évident maintenant).

Donc, en utilisant ce calcul du temps de bit CAN j'ai trouvé les bons réglages. Pour cela, j'ai eu besoin de mon APB1 peripheral clocks et le débit en bauds souhaité (pour moi, ce sont 24MHz et 125kbps). J'ai utilisé la fréquence préférée sample point y SJW Les valeurs recommandées par l'outil sont 87,5% et 1. Le tableau suivant est alors généré : https://i.stack.imgur.com/ENshf.png

Il est ensuite assez simple de remplir les champs STM32CubeIDE des paramètres de temporisation des bits : https://i.stack.imgur.com/V1q61.png

Et tada, le TXOKx est à 1 et TERRx à 0.

En bonus, voici un petit bout de code qui récupère l'adresse de l'utilisateur. LEC que j'ai écrit. Il n'est pas destiné à être utilisé dans une application entièrement fonctionnelle, il est juste destiné à être testé.

//adds a message to transmit and obtains "allocated" TxMailbox
HAL_CAN_AddTxMessage(hcan, &TxHeader, TxData, &TxMailbox);

//waiting for message to leave
while(HAL_CAN_IsTxMessagePending(&hcan1, TxMailbox));

//waiting for transmission request to be completed by checking RQCPx
while( !(hcan->Instance->TSR & ( 0x1 << (7 * ( TxMailbox - 1 )))));

//checking if there is an error at TERRx, may be done with TXOKx as well (i think)
if ((hcan->Instance->TSR & ( 0x8 << (7 * ( TxMailbox - 1 ))))){
    //error is described in ESR at LEC last error code
    uint8_t error_code = ( hcan->Instance->ESR & 0x70 ) >> 4;
    //000: No Error
    //001: Stuff Error
    //010: Form Error
    //011: Acknowledgment Error
    //100: Bit recessive Error
    //101: Bit dominant Error
    //110: CRC Error
    //111: Set by software
    while (1);
}

J'espère que ma réponse n'était pas trop en rapport avec le sujet et qu'elle peut être considérée comme une première contribution acceptable selon la politique de Stack Overflow.

1voto

HelpingHand Points 1123
  • [...] lorsque la transmission est entièrement accomplie et que les données deviennent disponibles sur le bus CAN, les bits TME, RQCP et TXOK du registre CAN_TSR sont activés par le matériel, montrant que la boîte aux lettres correspondante est devenue vide et que la transmission a été effectuée avec succès.

    Lorsque je débogue le programme suivant, aucun des changements mentionnés ne se produit dans le registre CAN_TSR.

    Le périphérique CAN ("bxCAN") du STM32F103xx comprend trois TX FIFO. Il y a donc trois instances de ( TMEx, RQCPx, TXOKx ) pour vérifier - juste pour être sûr.

  • Je vois seulement que le bit TME est activé, ce qui signifie qu'une boîte aux lettres est prévue pour la transmission mais n'est jamais transmise.

    Il semble y avoir une erreur dans l'interprétation des bits TME dans CAN_TSR : Comme vous pouvez le vérifier dans la sec. 24.9.2 (pages 677-8) de la Manuel de référence du STM32F103 , Les bits TME sont "activé par le matériel lorsqu'aucune demande de transmission n'est en attente pour la boîte aux lettres". . Donc, si on trouve ces bits set alors la transmission semble être déjà terminée.

  • Si la transmission reste en attente, il se peut qu'elle se soit bloquée en raison de conditions d'erreur. Qu'en est-il des compteurs d'erreurs (REC/TEC) dans le registre CAN_ESR ?

    Si aucun récepteur n'est à l'écoute, un émetteur CAN passera en mode d'erreur car les bits d'accusé de réception des récepteurs ne parviennent pas à l'émetteur. L'exemple de code ne montre pas d'instructions GPIO d'activation pour les broches CAN. Cela devrait être OK avec le mode loopback, mais je n'ai jamais essayé moi-même.

  • Il se peut que la transmission soit en attente parce que le composant bxCAN reste dans son mode d'initialisation Voir la section 24.4.1 (page 657) du manuel de référence. Ensuite, le logiciel doit déclencher la transition vers mode normal . Je ne suis pas sûr que HAL_CAN_Init() comprend ceci.

  • La variable TxMailbox n'est jamais initialisé dans le code utilisateur. S'il est affecté par la fonction HAL_CAN_AddTxMessage() c'est bien. Si ce n'est pas le cas, HAL_CAN_IsTxMessagePending() sera interrogé à une mauvaise adresse de boîte aux lettres (peut-être pour toujours).

  • La fonction HAL_CAN_AddTxMessage() est appelé deux fois (une fois en rejetant sa valeur de retour, la seconde fois en la vérifiant. Ceci est susceptible de causer d'autres problèmes (multiple-TX), mais je ne vois pas de relation avec le problème actuel de no-TX.

  • DLC est fixé à 1, mais le message est long de 5 octets. Lorsque la transmission commence à fonctionner, elle ne transmet qu'un 'H' mais 'E','L','L','O' sera manquant.


Mise à jour : J'ai vérifié le documentation du HAL du STM32CubeF1 . La section 9.2 (page 92) décrit comment initialiser CAN via le pilote HAL de ST :

  1. Exécuter __HAL_RCC_CANx_CLK_ENABLE() .

    • Je ne vois pas cela dans l'exemple de code. A vérifier...
  2. Initialiser le périphérique CAN en utilisant HAL_CAN_Init() .

    • C'est ce qui est fait dans l'exemple de code. OK.
  3. Configurez les filtres de réception en utilisant HAL_CAN_ConfigFilter() .

    • Cela manque, mais je ne pense pas que ce soit la raison pour laquelle le TX ne fonctionne pas.
  4. Démarrez le module CAN en utilisant HAL_CAN_Start() .

    • Je pense que c'est l'appel de fonction manquant. Je n'ai pas vérifié son code, mais je suppose que cette fonction s'occupe également de la fonction INRQ / SLEEP drapeaux. C'est le meilleur candidat pour l'origine du problème !
  5. Affectations HAL_CAN_AddTxMessage() et autres.

    • Mais ceci est conforme à l'exemple de code. OK.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X