STM32F107 transplantation canfestival

brief introduction

The following is a porting record of the canfestival protocol stack when learning Canopen. The reference links are strongerhuang.

Platform introduction

  • MCU : STM32F107VCT6
  • RTOS : RT-Thread RTOS
  • ST_Lib : STM32F1xx HAL Driver version number V1.1.4
  • Compiler: MDK 5.28

canfestival

  • Source: Enter Official website of canfestival Download.Click the Code option and continue clicking the code.html.en link from the page to enter the source selection, where you select the type source with the professional support identifier (second item in the Repositories list); click the Documentation option and continue clicking doc.html.en from the page.The link goes into the documentation, which includes a PDF manual and an object dictionary editing tool (Objdictedit).
  • Object Dictionary Editing: The downloaded source compression package contains an object dictionary containing a tool (Objdictedit), which requires Python environment support to run.To use this tool to directly generate object dictionaries, install Python-2.7.15 and wxPython 2.8; when the environment is set up, go to the folder where the source compression package is extracted, unzip the objdictgen/Gnosis_Utils-current.tar.gz compression package, and extract the folder named gnosis inside the unzipped folder, copy it to the objdictgen/directory, and open the objdictgen/objdictedit.py is ready to run the Objdictedit tool.

Source File Extraction

  • src folder: only the.C file in this directory is needed, but symbols.c is not used, and timer.c is best to change the file name to prevent name conflicts within the project.
  • Incude folder: All.h files in this directory, as well as.h files in the cm4 folder, note the file name.
  • examples folder: The config.h file of the AVR/Slave/directory under this folder is required.

    drivers folder: Some porting references are provided under this folder, such as the cm3, cm4 folders, and the provided porting examples are based on standard libraries.

Transplantation process

  • Prepare a normal project, copy the files described above, and add these.c files to the project with the.h file path.
  • Open the copied dcf.c file and delete the inline declarations for inline void start_node(CO_Data* d, UNS8 nodeId) and inline void start_and_seek_node(CO_Data* d, UNS8 nodeId) under the file, at lines 59 and 98, respectively.
  • Open the copied canfentival.h file and add three #ifndef #define #endif to it.
  • Open the copied config.h, delete or block the following
#ifdef  __IAR_SYSTEMS_ICC__
#include <ioavr.h>
#include <intrinsics.h>
#include "iar.h"
#else   // GCC
#include <inttypes.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
#include <avr/sleep.h>
#include <avr/wdt.h>
#endif  // GCC
//#define WD_SLEEP
// Needed defines by Atmel lib
#define FOSC           8000        // 16 MHz External cristal
#ifndef F_CPU
#define F_CPU          (1000UL*FOSC) // Need for AVR GCC
#endif
#define CAN_BAUDRATE    250

Modify #define REPEAT_SDO_MAX_SIMULTANEOUS_TRANSFERTS_TIMES(repeat)\ to #define REPEAT_SDO_MAX_SIMULTANEOUS_TRANSFERS_TIMES(repeat), deleting the T character in TRANSFERTS.

Implement API functionality

Some functions need to be implemented by themselves after canfestival migration, such as the two functions declared in timer.h, which are related to timers within the protocol stack.

/**
 * @ingroup timer
 * @brief Set a timerfor a given time.
 * @param value The time value.
 */
void setTimer(TIMEVAL value);

/**
 * @ingroup timer
 * @brief Get the time elapsed since latest timer occurence.
 * @return time elapsed since latest timer occurence
 */
TIMEVAL getElapsedTime(void);

Functions declared in canfestival.h can be called directly after they have been implemented, or users can use custom functions to implement these functions.

void initTimer(void);
void clearTimer(void);

unsigned char canSend(CAN_PORT notused, Message *m);
unsigned char canInit(CO_Data * d, uint32_t bitrate);
void canClose(void);

void disable_it(void);
void enable_it(void);

The drivers folder mentioned above can be used as a reference for these interface implementations.

Personal Transplantation Program

  • setTimer and getElapsedTime:
static TIMEVAL last_counter_val = 0;
static TIMEVAL elapsed_time = 0;
void setTimer(TIMEVAL value)
{
    uint32_t timer = __HAL_TIM_GET_COUNTER(&can_tim);
    elapsed_time += timer - last_counter_val;
    last_counter_val = CANOPEN_TIM_PERIOD - value;
    __HAL_TIM_SET_COUNTER(&can_tim, CANOPEN_TIM_PERIOD - value);
    HAL_TIM_Base_Start_IT(&can_tim);
}
TIMEVAL getElapsedTime(void)
{
    uint32_t timer = __HAL_TIM_GET_COUNTER(&can_tim);

    if(timer < last_counter_val)
    {
        timer += CANOPEN_TIM_PERIOD;
    }

    TIMEVAL elapsed = timer - last_counter_val + elapsed_time;
    return elapsed;
}
  • initTimer:
void initTimer(void)
{
    can_tim.Instance               = CANOPEN_TIMER;
    can_tim.Init.Prescaler         = CANOPEN_PRESCALER;
    can_tim.Init.CounterMode       = TIM_COUNTERMODE_UP;
    can_tim.Init.Period            = CANOPEN_TIM_PERIOD;
    can_tim.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
    HAL_TIM_Base_Init(&can_tim);
    __HAL_TIM_SET_COUNTER(&can_tim, 0);
    HAL_TIM_Base_Start_IT(&can_tim);
}
  • canInit:
unsigned char canInit(CAN_HandleTypeDef *handle)
{
    CAN_FilterTypeDef hcan_filter;

    //CAN2 Controller Configuration
    handle->Instance = CANOPEN_HANDLE;
    handle->Init.Prescaler = presc;
    handle->Init.Mode = CAN_MODE_NORMAL;
    handle->Init.SyncJumpWidth = sjw;
    handle->Init.TimeSeg1 = ts1;
    handle->Init.TimeSeg2 = ts2;
    handle->Init.TimeTriggeredMode = DISABLE;
    handle->Init.AutoBusOff = DISABLE;
    handle->Init.AutoWakeUp = DISABLE;
    handle->Init.AutoRetransmission = DISABLE;
    handle->Init.ReceiveFifoLocked = DISABLE;
    handle->Init.TransmitFifoPriority = DISABLE;
    HAL_CAN_Init(handle);

    //CAN Filter Configuration
    hcan_filter.FilterBank = 14;
    hcan_filter.FilterMode = CAN_FILTERMODE_IDMASK;
    hcan_filter.FilterActivation = CAN_FILTER_ENABLE;
    hcan_filter.FilterFIFOAssignment = CAN_FILTER_FIFO0;
    hcan_filter.FilterScale = CAN_FILTERSCALE_32BIT;
    hcan_filter.FilterIdHigh = 0x0000;
    hcan_filter.FilterIdLow = 0x0000;
    hcan_filter.FilterMaskIdHigh = 0x0000;
    hcan_filter.FilterMaskIdLow = 0x0000;
    hcan_filter.SlaveStartFilterBank = 14;
    HAL_CAN_ConfigFilter(handle, &hcan_filter);

    //Start CAN2 to enable interruption
    HAL_CAN_Start(handle);
    HAL_CAN_ActivateNotification(handle, CAN_IT_RX_FIFO0_MSG_PENDING);

    return 0;
}
  • canSend:
unsigned char canSend(CAN_PORT notused, Message *m)
{
    struct Can_Tx pre_send;

    pre_send.TxInfo.StdId = m->cob_id;

    if(m->rtr)
        pre_send.TxInfo.RTR = CAN_RTR_REMOTE;
    else
        pre_send.TxInfo.RTR = CAN_RTR_DATA;

    pre_send.TxInfo.IDE = CAN_ID_STD;
    pre_send.TxInfo.DLC = m->len;

    for(int i = 0; i < m->len; i++)
    {
        pre_send.Tx_data[i] = m->data[i];
    }

    if(rt_mq_send(can_txmq, &pre_send, sizeof(pre_send)) != RT_EOK)
        return 0xff;

    return 0;
}
  • Callback function:
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
    if(htim == (&can_tim))
    {
        last_counter_val = 0;
        elapsed_time = 0;
        TimeDispatch();
    }
}
void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan)
{
    struct Can_Rx rs_msg;
    HAL_CAN_GetRxMessage(&canopen, CAN_RX_FIFO0, &rs_msg.RxInfo, rs_msg.Rx_data);
    rt_mq_send(can_rxmq, &rs_msg, sizeof(rs_msg));
    HAL_CAN_ActivateNotification(hcan, CAN_IT_RX_FIFO0_MSG_PENDING);
}

Receive and receive functions as separate tasks, queued

  • Receive Task: Get data from receive queue, extract corresponding parameters into Message type variable, put into protocol stack
if(rt_mq_recv(can_rxmq, &mq_recv, sizeof(mq_recv), RT_WAITING_FOREVER) == RT_EOK)
{            
    rxmsg.cob_id = mq_recv.RxInfo.StdId;
    if(mq_recv.RxInfo.RTR == CAN_RTR_REMOTE)
        rxmsg.rtr = 1;
    else
        rxmsg.rtr = 0;
    rxmsg.len = (UNS8)mq_recv.RxInfo.DLC;
    for(int i = 0; i < mq_recv.RxInfo.DLC; i++)
    {
        rxmsg.data[i] = mq_recv.Rx_data[i];
    }
    HAL_TIM_Base_Stop_IT(&can_tim);
    canDispatch(&center_Data, &rxmsg);
    HAL_TIM_Base_Start_IT(&can_tim);
}
  • Send Task: Receive data from send queue, call send interface
if(rt_mq_recv(can_txmq, &msg_send, sizeof(msg_send), RT_WAITING_FOREVER) == RT_EOK)
{
    HAL_CAN_AddTxMessage(&canopen, &msg_send.TxInfo, msg_send.Tx_data, &TxMailbox);
}

summary

The above is the ported content. After the porting is completed, the protocol stack can be started after the task initialization CAN is established.Novice on the road, the inadequacies hope to point out that common learning.

Tags: C Python

Posted on Tue, 10 Mar 2020 20:24:28 -0700 by nolos