Page tree

Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

Code Block
titleLibcanard initialization
CanardInstance g_canard;   					//The library instance
static uint8_t g_canard_memory_pool[1024]; 	//Arena for memory allocation, used by the library

static void swInit(void)
{
    int result = 0;
    CanardSTM32CANTimings timings;
    result = canardSTM32ComputeCANTimings(RCC_Clocks.PCLK1_Frequency, 1000000, &timings);
    if(result)
    {
        __ASM volatile("BKPT #01"); 
    }
    result = canardSTM32Init(&timings, CanardSTM32IfaceModeNormal);
    if(result)
    {
        __ASM volatile("BKPT #01"); 
    }
  
    canardInit(&g_canard,                           // Uninitialized library instance
               canard_memory_pool,                // Raw memory chunk used for dynamic allocation
               sizeof(canard_memory_pool),        // Size of the above, in bytes
               onTransferReceived,                // Callback, see CanardOnTransferReception
               shouldAcceptTransfer,              // Callback, see CanardShouldAcceptTransfer
               NULL); 
    
    canardSetLocalNodeID(&canard, 100);
}

...

Code Block
titleonTransferReceived
void onTransferReceived(CanardInstance* ins, CanardRxTransfer* transfer)
{
    if ((transfer->transfer_type == CanardTransferTypeRequest) &&
    (transfer->data_type_id == UAVCAN_GET_NODE_INFO_DATA_TYPE_ID))
    {
        canard_get_node_info_handlecanardGetNodeInfoHandle(transfer);
    } 
}

As it is obvious from shouldAcceptTransfer our node will accept only one type of messages:

...

Code Block
titlecanard_service
#define CANARD_SPIN_PERIOD    1000


void canard_servicespinCanard(void)
{
	    static uint32_t servicespin_time = 0;
      if(get_uptimegetUptime() < servicespin_time + CANARD_SPIN_PERIOD) return; // to enter this function only once a period
    servicespin_time = get_uptimegetUptime();
    gpio_togglegpioToggle(GPIOE, GPIO_Pin_8);                           //some indication

     uint8_t buffer[UAVCAN_NODE_STATUS_MESSAGE_SIZE];
    static uint8_t transfer_id = 0;

    makeNodeStatusMessage(buffer);

    canardBroadcast(&canard, 
                    UAVCAN_NODE_STATUS_DATA_TYPE_SIGNATURE,
	    			UAVCAN_NODE_STATUS_DATA_TYPE_ID,
        			&transfer_id,
        			CANARD_TRANSFER_PRIORITY_LOW,
	    			buffer, 
	    			UAVCAN_NODE_STATUS_MESSAGE_SIZE);
}

...

Code Block
titlecanard_get_node_info_handle
#define APP_VERSION_MAJOR   					99
#define APP_VERSION_MINOR   					99
#define APP_NODE_NAME   						"com.zubax.babel.demo"
#define GIT_HASH								0xBADC0FFE
#define UAVCAN_GET_NODE_INFO_RESPONSE_MAX_SIZE  ((3015 + 7) / 8)

uint16_t makeNodeInfoMessage(uint8_t buffer[UAVCAN_GET_NODE_INFO_RESPONSE_MAX_SIZE])
{
    memset(buffer, 0, UAVCAN_GET_NODE_INFO_RESPONSE_MAX_SIZE);
    makeNodeStatusMessage(buffer);

    buffer[7] = APP_VERSION_MAJOR;
    buffer[8] = APP_VERSION_MINOR;
    buffer[9] = 1;  // Optional field flags, VCS commit is set
    uint32_t u32 = GIT_HASH;
    canardEncodeScalar(buffer, 80, 32, &u32); 

    readUniqueID(&buffer[24]);
    const size_t name_len = strlen(APP_NODE_NAME);
    memcpy(&buffer[41], APP_NODE_NAME, name_len);
    return 41 + name_len ;
}

void canardGetNodeInfoHandlegetNodeInfoHandleCanard(CanardRxTransfer* transfer)
{
    uint8_t buffer[UAVCAN_GET_NODE_INFO_RESPONSE_MAX_SIZE];
    memset(buffer,0,UAVCAN_GET_NODE_INFO_RESPONSE_MAX_SIZE);
    uint16_t len = 0;
    len = makeNodeInfoMessage(buffer);
    int result = canardRequestOrRespond(&g_canard,
                                        transfer->source_node_id,
                                        UAVCAN_GET_NODE_INFO_DATA_TYPE_SIGNATURE,
                                        UAVCAN_GET_NODE_INFO_DATA_TYPE_ID,
                                        &transfer->transfer_id,
                                        transfer->priority,
                                        CanardResponse,
                                        &buffer[0],
                                        (uint16_t)len);
}

...

Code Block
titlemain
int main(void)
{ 
    /*!< At this stage the microcontrollers clock setting is already configured, 
       this is done through SystemInit() function which is called from startup
       file (startup_stm32f37x.s) before to branch to application main.
       To reconfigure the default setting of SystemInit() function, refer to
       system_stm32f37x.c file */
    RCC_GetClocksFreq(&RCC_Clocks); //To make sure RCC is initialised properly
    hwInit();
    swInit();  
    SysTick_Config(SystemCoreClock / 1000); //To make systick event happen every 1 mS
    while(1)
    {
        canardSendsendCanard();
        canardReceivereceiveCanard();
        canardSpinspinCanard();
    }
}

The only interrupt used in the application is SysTick interrupt for uptime counter with 1 mS resolution.

Code Block
titlesystick_isr
void systickIsr(void);
uint32_t getUptime(void);

static uint32_t  g_uptime = 0;

uint32_t getUptime(void)
{
    return g_uptime;
}

void systickIsr(void)
{
    g_uptime++;
}

As libcanard does not use any interrupts it is up to user when and how to receive and transmit UAVCAN messages. In this application we will constantly poll if any message was received by MCU CAN peripheral and process it. We will also poll if library has any new messages to transmit and manually extract them from the library and pass to CAN transmitter.

Code Block
titlecanard_sender
void canardSendsendCanard(void)
{
    const CanardCANFrame* txf = canardPeekTxQueue(&g_canard); 
    while(txf)
    {
        const int tx_res = canardSTM32Transmit(txf);
        if (tx_res < 0)         // Failure - drop the frame and report
        {
            __ASM volatile("BKPT #01"); 
        }
        if(tx_res > 0)
        {
            canardPopTxQueue(&g_canard);
        }
        txf = canardPeekTxQueue(&g_canard); 
    }
}

...

Code Block
titlecanard_receive
void canardReceivereceiveCanard(void)
{
    CanardCANFrame rx_frame;
    int res = canardSTM32Receive(&rx_frame);
    if(res)
    {
        canardHandleRxFrame(&canard, &rx_frame, get_uptime() * 1000);
    }    
}

...