CAN bus demo from template on SAMe54 Xplained Pro - gneidermeier/CANFDDemo_SAMe54_START GitHub Wiki
This guide covers a basic demonstration of the SAM E54 Xplained Pro eval board.
Our purpose for evaluating the SAMe54 is specifically to garner expertise with CAN-bus communication. CAN is a "multi-master serial bus standard for connecting Electronic Control Units [ECUs]" - please refer to the cited article or other resource if not familiar with CAN-bus.
In this guide, the Atmel START web based graphical configuration tool is used to generate a simple template project (LED Flasher demo). The example will be modified to demonstrate communication between the eval board and a PC over the CAN-bus.
Requirements (see setup instructions on previous page):
- SAM E54 Xplained Pro eval board
Generating and importing starter project into Atmel Studio
- Open Atmel START web based graphical configuration tool and click BROWSE EXAMPLES
- Filter by Category: (e.g. I/O) and/or Board: (e.g. SAM E54 Xplained Pro)
- Select LED flasher and click Download Selected Example
- In Atmel Studio, [File | Import | Atmel Start Project] and select the downloaded project bundle LED flasher.atzip
- Build (F7) and Debug (F5)
Configure clocks
Digital Phase Locked Loop (DPLL) component is essential for generating higher clock rate to the CPU, as well as various peripherals such as CAN bus which might require custom clock timing from a stable source.
- In Atmel Studio open the Atmel START configuration tool from [ Project | Update Atmel Start Project from Start file ] and select the CLOCKS tab
- Click the checkbox in Generic clock generator 1 (GCLK1).
- Click the gear icon on GCLK1 component - in the CLOCK SETTINGS dialog set Generic clock generator 1 source to XOSC1
- In the CLOCK SETTINGS dialog, the Generic clock generator 1 division should be changed to 12.
- Click Close on the CLOCK SETTINGS dialog (GCLK1 component label should indicate output frequency of 1 MHz)
- On the CLOCKS tab, click the checkbox in Digital Phase Locked Loop (DPLL0).
- Click the gear icon on DPLL0 component - in the CLOCK SETTINGS dialog set Reference Clock Source to Generic clock generator 1
- In the CLOCK SETTINGS dialog, set Loop Divider Ratio Fractional Part to 0
- Set Loop Divider Ratio Integer Part to 119
- Set Reference Clock Selection to GCLK clock reference
- Click Close on the CLOCK SETTINGS dialog (DPLL0 component label should indicate output frequency of 120 MHz)
With the DPLL configured, CPU frequency can be increased to 120 MHz:
- Click the gear icon on Generic clock generator 0 component - in the CLOCK SETTINGS dialog, set Generic clock generator 0 source to Digital Phase Locked Loop (DPLL0)
- Click Close on the CLOCK SETTINGS dialog (GCLK0 component label should indicate output frequency of 120 MHz)
- Click GENERATE PROJECT, click OK on Project Summary to accept the changes.
At this point, should be possible to compile/debug/run the project and observe LED0 flashing steadily - frequency of toggling LED0 can be changed faster or slower merely by adjusting parameter passed to os_sleep()
e.g.
static void task_led(void *p)
{
(void)p;
for (;;) {
gpio_toggle_pin_level(LED0);
os_sleep(100);
}
}
Installing a timer to execute periodic task
The LED Flasher example should be working on the SAMe54 with no additional modification, flashing the onboard LED at a definite interval. This is done in the background task (while()) and as such, is adequate for the example. However, the timing is established by looping over delay_ms(), which may not be especially robust. An instance of the SAMe54 timer peripheral can be added easily to provide a more stable timing reference for periodic task execution.
- Choose "Project | Re-Configure Atmel Start Project"
- On DASHBOARD tab click Add software component - OR - on CLOCK CONFIGURATOR tab, click + icon next to COMPONENTS
- In ADD SOFTWARE COMPONENTS dialog, expand Drivers, select Timer, click Add component(s)
- On DASHBOARD tab, click gear icon in TIMER_0 component that was just added
- Under COMPONENT SETTINGS open the Instance drop-down menu and Select TC0
- Under CLOCKS open the TC drop-down menu and select Generic clock generator 0
- Still on DASHBOARD tab, under BASIC CONFIGURATION section set Prescaler drop-down menu to Divide by 1024 and timer tick in uS should be 1000 (default)
- Click GENERATE PROJECT
Insert the timer driver initialization in main()
, prior to entering infinite while() loop - add the invocation of TIMER_0_example()
i.e.:
TIMER_0_example(); // initialize timer peripheral
int main(void)
{
atmel_start_init();
while (true) {
delay_ms(500);
// gpio_toggle_pin_level(LED0); // remove me
}
}
Note the removal of the LED toggle of the flasher example - open the generated file driver_examples.c and insert a copy of the one line that toggles the LED into the timer task callback function:
static void TIMER_0_task1_cb(const struct timer_task *const timer_task)
{
gpio_toggle_pin_level(LED0);
}
The LED should be seen toggling at a rate consistent with the assigned TIMER_0_task1.interval
e.g. 100mS. The initialization of the timer peripheral in TIMER_0_example() created an additional timer task callback which will be used later in the tutorial.
static void TIMER_0_task2_cb(const struct timer_task *const timer_task)
{
// do something here
}
Add serial port output
It is quite useful to monitor the application by sending printf() to a terminal.
From Atmel START window, adding the Target IO component:
- In Atmel START, switch to DASHBOARD tab, click Add software component
- Expand Middleware, expand Utilities, select STDIO Redirect, click Add component(s) (TARGET_IO driver dependency automatically added)
- Click gear icon on TARGET_IO component
- Change COMPONENT SIGNALS set RX and TX to PB24 and PB25 respectively
- Under COMPONENT SETTINGS, set Instance to SERCOM2
- Change Baud rate to 115200
- Click on CLOCKS tab, then click enable on Generic clock generator 3 (GCLK3)
- On CLOCKS tab, click enable on 32KHz External Crystal (XOSC32K)
- On GCLK3, and click gear icon, set source of GCLK3 to XOSC32K and set generic clock generator 3 division to 1
- Click close - output frequency of GCLK3 should be 32.768 kHz, thus sourcing the Slow clock to TARGET_IO component
- Click GENERATE PROJECT (WARNING files modified will be overwritten), then OK on Project Summary dialog
Timer callback with terminal output:
static void TIMER_0_task2_cb(const struct timer_task *const timer_task)
{
static ddd;
printf("TIMER_0_task2_cb %X\r\n", ddd++);
}
Add CAN peripheral
A CAN-bus peripheral driver component is available in Atmel START. An timer task can be used to demonstrate transmission of a series of CAN messages from the SAMe54. The CAN peripheral requires a clock source - this example will utilize a 40 MHz clock source (based on CAN FD Demo example). In the clock setup section above, DPLL0 component was added and configured to provide such a clock reference, but it must be further adjusted to generate 40 MHz.
Set up clock source
- Change to CLOCKS tab of Atmel START, click enable checkbox in Generic clock generator 2 source (GCLK2)
- Click the gear icon on GCLK2 source
- In CLOCK SETTINGS, change Generic clock generator 2 source to DPLL0
- Uncheck Divide Selection, check Output Enable
- In Generic clock generator 2 division enter 3
- Click Close on the CLOCK SETTINGS dialog (CAN_0 component label should indicate output frequency of 40 MHz)
Add CAN driver component
- In Atmel START, switch to DASHBOARD tab, click Add software component
- In ADD SOFTWARE COMPONENTS dialog, expand Drivers, select CAN and click Add component(s)
- Click the gear icon on CAN_0 component
- Under CLOCKS set CAN to Generic clock generator 2
- Under COMPONENT SIGNALS set RX and TX to pins PB13 & PB12 respectively
- Driver Instance should indicate CAN1
- Under NORMAL BIT TIMING AND PRESCALER, enter the values 1, 59, 20, 15 for BRP, time segment before, time segment after and Synchronization Jump Width respectively
- Click GENERATE PROJECT (WARNING files modified will be overwritten)
NOTE: BIT TIMINGs were copied from "CAN FD Example" and does not justify the actual timing register values being used.
A little more Copy-and-paste programming should have the CAN-bus working on the SAMe54 and should be possible to transmit CAN message from SAMe54 board.
Add the following GPIO pin definition to atmel_start_pins.h:
#define CAN_STDBY GPIO(GPIO_PORTC, 13)
Add the GPIO pin setup into system_init()
in driver_init.c:
void system_init(void)
{
init_mcu();
gpio_set_pin_level(CAN_STDBY, false);
// Set pin direction to output
gpio_set_pin_direction(CAN_STDBY, GPIO_DIRECTION_OUT);
gpio_set_pin_function(CAN_STDBY, GPIO_PIN_FUNCTION_OFF);
Finally, add a periodic message generation to a timer callback e.g.:
static void TIMER_0_task2_cb(const struct timer_task *const timer_task)
{
CAN_0_example();
}
Please see the accompanying CAN FD guide for more detail how to setup CAN-bus and monitoring tool.
Monitoring CAN-bus on SAMe54
The CAN_0_rx_callback()
can be modified to show received CAN messages in the terminal window:
void CAN_0_rx_callback(struct can_async_descriptor *const descr)
{
struct can_message msg;
uint8_t data[64];
msg.data = data;
can_async_read(descr, &msg);
printf("%04X: %02X %02X %02X %02X %02X %02X %02X %02X\r\n",
msg.id, data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7]);
return;
}
Generating test messages from PCANView
Please see the previous guide for more detail how to setup CAN-bus and monitoring tool to generate test messages onto CAN-bus from PCANView monitoring tool.