Si vous devez réaliser un projet avec la carte Atmel SAM4S-EK, il faudra vous organiser et structurer celui-ci.
Pour commencer, vous devez créer un répertoire contenant l’ensemble de votre code source.
Vous placerez dans celui-ci les fichiers suivants :
Makefile
: un fichier générique lu par la commande make
(ici il inclut le fichier Makefile.sam.in
qui est le véritable Makefile)config.mk
: ce fichier qui contient le paramétrage spécifique au projet est lu par le fichier Makefile
main.c
: le programme principal du projetasf.h
: ce fichier en-tête (header) inclut les autres fichiers d’en-tête ASF nécessaire pour le projetRemarque : ces fichiers sont paramétrables
Vous pouvez utiliser aussi les deux scripts suivants :
run.sh
: ce script permet de flasher un programme sur la carte (cf. Annexe n°1)clean.sh
: ce script permet d’effacer les fichiers temporaires du répertoire courant (cf. Annexe n°2)On y ajoute ensuite les répertoires suivants :
include
: ce répertoire contiendra les fichiers header .h
spécifiques au projetdoxygen
: ce répertoire contiendra la documentation au format HTML du code source générée par doxygen et son fichier de configuration doxyfile.doxygen
Remarque : voir aussi Annexe n°3
main.c
Son squelette est le suivant :
#include <asf.h>
int main (void)
{
board_init();
sysclk_init();
return 0;
}
La fonction main()
appelle généralement les fonctions board_init()
et sysclk_init()
:
board_init()
est définie dans le fichier source /usr/local/asf/sam/boards/sam4s_ek/init.c
et a pour rôle d’initialiser l’ensemble des composants de la carte de développement SAM4S-EK.sysclk_init()
est définie dans le fichier source /usr/local/asf/common/services/clock/sam4s/sysclk.c
(d’autres fonctions utilisées se situent dans /usr/local/asf/sam/utils/cmsis/sam4s/source/templates/system_sam4s.c
) et a pour rôle d’initialiser les horloges systèmes.conf_board.h
L’initialisation des composants de la carte de développement SAM4S-EK réalisée la fonction board_init()
dépend des étiquettes définies dans un fichier spécifique au projet include/conf_board.h
:
#ifndef CONF_BOARD_H_INCLUDED
#define CONF_BOARD_H_INCLUDED
/** Enable Com Port. */
#define CONF_BOARD_UART_CONSOLE
/** Usart Hw ID used by the console (UART0). */
#define CONSOLE_UART_ID ID_UART0
/* Configure ADC pins (TC TIOA, ADC Trigger & PWMH0 configuration) */
//#define CONF_BOARD_ADC
/* Configure PWM LED0 pin */
//#define CONF_BOARD_PWM_LED0
/* Configure PWM LED1 pin */
//#define CONF_BOARD_PWM_LED1
/* Configure PWM LED2 pin */
//#define CONF_BOARD_PWM_LED2
//#define CONF_BOARD_TWI0
//#define CONF_BOARD_TWI1
/* Configure SPI pins */
//#define CONF_BOARD_SPI
/*
* For NPCS 1, 2, and 3, different PINs can be used to access the same NPCS line.
* Depending on the application requirements, the default PIN may not be available.
* Hence a different PIN should be selected using the CONF_BOARD_SPI_NPCS_GPIO and
* CONF_BOARD_SPI_NPCS_FLAGS macros.
*/
//#define CONF_BOARD_SPI_NPCS0
//#define CONF_BOARD_SPI_NPCS1
//#define CONF_BOARD_SPI_NPCS2
//#define CONF_BOARD_SPI_NPCS3
//#define CONF_BOARD_USART_RXD
//#define CONF_BOARD_USART_TXD
//#define CONF_BOARD_USART_CTS
//#define CONF_BOARD_USART_RTS
//#define CONF_BOARD_USART_SCK
/* Configure ADM33312 enable pin (USART RS232) */
//#define CONF_BOARD_ADM3312_EN
/* Configure IrDA transceiver shutdown pin */
//#define CONF_BOARD_TFDU4300_SD
/* Configure RS485 transceiver RE pin */
//#define CONF_BOARD_ADM3485_RE
/* Indicates board has an AAT3155 external component to control LCD backlight */
//#define CONF_BOARD_AAT3155
/* Indicates board has an ILI93xx external component to control LCD */
//#define CONF_BOARD_ILI9325
/* Configure Touchscreen SPI pins */
//#define CONF_BOARD_ADS7843
/* Configure MMA7341L mode set control pin and x,y,z axis output voltage pin */
//#define CONF_BOARD_MMA7341L
/* Configure ISO7816 card reset pin */
//#define CONF_BOARD_ISO7816_RST
/* Configure ISO7816 interface TXD & SCK pin */
//#define CONF_BOARD_ISO7816
//#define CONF_BOARD_NAND
/* Configure HSMCI pins and SD/MMC card detect pin */
//#define CONF_BOARD_SD_MMC_HSMCI
//#define CONF_BOARD_USB_PORT
#endif /* CONF_BOARD_H_INCLUDED */
Il suffit alors de décommenter la définition des étiquettes correspondant aux périphériques dont vous avez besoin.
conf_clock.h
La fonction sysclk_init()
pourra personnaliser son initialisation en fonction des définitions du fichier spécifique au projet include/conf_clock.h
:
#ifndef CONF_CLOCK_H_INCLUDED
#define CONF_CLOCK_H_INCLUDED
// ===== System Clock (MCK) Source Options
//#define CONFIG_SYSCLK_SOURCE SYSCLK_SRC_SLCK_RC
//#define CONFIG_SYSCLK_SOURCE SYSCLK_SRC_SLCK_XTAL
//#define CONFIG_SYSCLK_SOURCE SYSCLK_SRC_SLCK_BYPASS
//#define CONFIG_SYSCLK_SOURCE SYSCLK_SRC_MAINCK_4M_RC
//#define CONFIG_SYSCLK_SOURCE SYSCLK_SRC_MAINCK_8M_RC
//#define CONFIG_SYSCLK_SOURCE SYSCLK_SRC_MAINCK_12M_RC
//#define CONFIG_SYSCLK_SOURCE SYSCLK_SRC_MAINCK_XTAL
//#define CONFIG_SYSCLK_SOURCE SYSCLK_SRC_MAINCK_BYPASS
#define CONFIG_SYSCLK_SOURCE SYSCLK_SRC_PLLACK
// ===== System Clock (MCK) Prescaler Options (Fmck = Fsys / (SYSCLK_PRES))
//#define CONFIG_SYSCLK_PRES SYSCLK_PRES_1
#define CONFIG_SYSCLK_PRES SYSCLK_PRES_2
//#define CONFIG_SYSCLK_PRES SYSCLK_PRES_4
//#define CONFIG_SYSCLK_PRES SYSCLK_PRES_8
//#define CONFIG_SYSCLK_PRES SYSCLK_PRES_16
//#define CONFIG_SYSCLK_PRES SYSCLK_PRES_32
//#define CONFIG_SYSCLK_PRES SYSCLK_PRES_64
//#define CONFIG_SYSCLK_PRES SYSCLK_PRES_3
// ===== PLL0 (A) Options (Fpll = (Fclk * PLL_mul) / PLL_div)
// Use mul and div effective values here.
#define CONFIG_PLL0_SOURCE PLL_SRC_MAINCK_XTAL
#define CONFIG_PLL0_MUL 20
#define CONFIG_PLL0_DIV 1
// ===== Target frequency (System clock)
// - XTAL frequency: 12MHz
// - System clock source: PLLA
// - System clock prescaler: 2 (divided by 2)
// - PLLA source: XTAL
// - PLLA output: XTAL * 20 / 1
// - System clock: 12 * 20 / 1 / 2 = 120MHz
#endif /* CONF_CLOCK_H_INCLUDED */
conf_uart_serial.h
On considère qu’il est important d’avoir un console pour afficher des messages de debug (avec printf()
par exemple) pendant le développement d’un projet. Pour cela, on utilise le port UART RS232.
Il se configure de la manière suivante :
/**
* \brief Configure UART console.
*/
static void configure_console(void)
{
const usart_serial_options_t uart_serial_options =
{
.baudrate = 115200,
.charlength = US_MR_CHRL_8_BIT,
.paritytype = UART_MR_PAR_NO,
.stopbits = US_MR_NBSTOP_1_BIT,
};
sysclk_enable_peripheral_clock(CONSOLE_UART_ID);
stdio_serial_init(CONSOLE_UART, &uart_serial_options);
}
Le fichier include/conf_uart_serial.h
existe pour paramètrer le port UART :
#ifndef CONF_USART_SERIAL_H
#define CONF_USART_SERIAL_H
/** UART Interface */
#define CONF_UART CONSOLE_UART
/** Baudrate setting */
#define CONF_UART_BAUDRATE 115200
/** Parity setting */
#define CONF_UART_PARITY UART_MR_PAR_NO
#endif/* CONF_USART_SERIAL_H_INCLUDED */
asf.h
Ce fichier header inclut les autres fichiers d’en-tête ASF nécessaire pour le projet. Étant spécifique, on le conservera à la racine du projet.
Voici un exemple de fichier minimal avec l’inclusion des fichiers pour le PIO (IOPORT/GPIO) et le port UART de debug notamment :
#ifndef ASF_H
#define ASF_H
/*
* This file includes all API header files for the selected drivers from ASF.
* Note: There might be duplicate includes required by more than one driver.
*
* The file is automatically generated and will be re-written when
* running the ASF driver selector tool. Any changes will be discarded.
*/
// From module: Common SAM compiler driver
#include <compiler.h>
#include <status_codes.h>
// From module: Delay routines
#include <delay.h>
// From module: Generic board support
#include <board.h>
// From module: GPIO - General purpose Input/Output
#include <gpio.h>
// From module: IOPORT - General purpose I/O service
#include <ioport.h>
// From module: Interrupt management - SAM implementation
#include <interrupt.h>
// From module: PDC - Peripheral DMA Controller Example
//#include <pdc.h>
// From module: PIO - Parallel Input/Output Controller
#include <pio.h>
// From module: PMC - Power Management Controller
#include <pmc.h>
#include <sleep.h>
// From module: Part identification macros
#include <parts.h>
// From module: SAM FPU driver
#include <fpu.h>
// From module: SAM4E EK LED support enabled
#include <led.h>
// From module: Standard serial I/O (stdio) - SAM implementation
#include <stdio_serial.h>
// From module: System Clock Control - SAM4E implementation
#include <sysclk.h>
// From module: TC - Timer Counter
#include <tc.h>
// From module: UART - Univ. Async Rec/Trans
#include <uart.h>
// From module: WDT - Watchdog Timer
#include <wdt.h>
// From module: pio_handler support enabled
#include <pio_handler.h>
#endif // ASF_H
config.mk
C’est le fichier le plus important puisqu’on y paramètre la fabrication du projet.
On commence par y indiquer le nom de l’exécutable dans la variable TARGET_FLASH
.
Puis la liste de ses fichiers sources dans la variable SRCS
.
Ensuite, on complète la liste des fichiers sources de la bibliothèque ASF dont on a besoin dans la variable CSRCS
.
Les variables les utilisées sont :
# Project type parameter: all, sram or flash
PROJECT_TYPE = flash
# Application target name. Given with suffix .a for library and .elf for a
# standalone application.
TARGET_FLASH = leds_flash.elf
# Target CPU architecture: cortex-m3, cortex-m4
ARCH = cortex-m4
# Target part: none, sam3n4 or sam4l4aa
PART = sam4s16c
# Path to top level ASF directory relative.
PRJ_PATH = /usr/local/asf
# Path to top level of this project directory.
MY_PATH = ./
# List of C source files for application
SRCS = main.c \
leds.c
# List of include paths for application
INCLUDE_PATH = . \
include
# List of C source files from ASF
CSRCS = \
common/services/clock/sam4s/sysclk.c \
common/services/delay/sam/cycle_counter.c \
common/services/serial/usart_serial.c \
common/utils/interrupt/interrupt_sam_nvic.c \
common/utils/stdio/read.c \
common/utils/stdio/write.c \
sam/boards/sam4s_ek/init.c \
sam/boards/sam4s_ek/led.c \
sam/drivers/pio/pio.c \
sam/drivers/pio/pio_handler.c \
sam/drivers/pmc/pmc.c \
sam/drivers/pmc/sleep.c \
sam/drivers/tc/tc.c \
sam/drivers/wdt/wdt.c \
sam/drivers/uart/uart.c \
sam/drivers/usart/usart.c \
sam/utils/cmsis/sam4s/source/templates/gcc/startup_sam4s.c \
sam/utils/cmsis/sam4s/source/templates/system_sam4s.c \
sam/utils/syscalls/gcc/syscalls.c \
${SRCS}
# List of include paths from ASF.
INC_PATH = \
common/boards \
common/services/clock \
common/services/delay \
common/services/gpio \
common/services/ioport \
common/services/serial \
common/services/serial/sam_uart \
common/utils \
common/utils/stdio/stdio_serial \
sam/boards \
sam/boards/sam4s_ek \
sam/drivers/pio \
sam/drivers/tc \
sam/drivers/pmc \
sam/drivers/wdt \
sam/drivers/uart \
sam/drivers/usart \
sam/utils \
sam/utils/cmsis/sam4s/include \
sam/utils/fpu \
sam/utils/header_files \
sam/utils/preprocessor \
thirdparty/CMSIS/Include \
thirdparty/CMSIS/Lib/GCC
# ...
Remarque : pour les autres variables, il faut s’inspirer des nombreux exemples fournis par ASF.
make
Le fichier Makefile
fourni offre de nombreuses cibles utilisables avec la commande make
.
Les plus utilisées sont :
make
: par défaut, cette commande fabrique l’exécutable dont le nom est contenu dans la variable TARGET_FLASH
make strip
: idem mais elle fabrique une version strippée de l’exécutable (éliminée de l’ensemble des information inutiles pour son exécution) donc plus légère en taillemake clean
: efface l’ensemble des fichiers issus de la fabricationmake debug_flash
: exécute le débugueur arm-none-eabi-gdb
(nécessite l’exécutation préalable de openocd
)make doc
: fabrique la documentation au format HTML dans le répertoire doxygen/html/
make cleandoc
: supprime la documentation au format HTML contenue dans le répertoire doxygen/html/
Dans un projet, vous aurez besoin de découper votre application en plusieurs fichiers sources contenant des fonctions que vous aurez créé. Vous devez configurer votre compilation dans le fichier config.mk
.
Vous pouvez placer vos fichiers d’en-têtes à la racine ou dans le répertoire include
.
Vous pouvez laisser vos fichiers sources à la racine de votre répertoire de projet mais il vous faudra renseigner la variable SRCS
en lui indiquant la liste de vos fichiers sources à compiler.
La bibliothèque logicielle ASF fourmille d’exemples notamment pour la carte Atmel SAM4S.
/usr/local/asf/sam/drivers/crccu/crccu_example/
/usr/local/asf/sam/drivers/usart/usart_iso7816_example/
/usr/local/asf/sam/drivers/usart/usart_hard_handshaking_example/
/usr/local/asf/sam/drivers/usart/usart_irda_example/
/usr/local/asf/sam/drivers/usart/usart_rs485_example/
/usr/local/asf/sam/drivers/usart/usart_synchronous_example/
/usr/local/asf/sam/drivers/usart/usart_serial_example/
/usr/local/asf/sam/drivers/rtc/example/
/usr/local/asf/sam/drivers/twi/twi_slave_example/
/usr/local/asf/sam/drivers/chipid/chipid_example/
/usr/local/asf/sam/drivers/pmc/pmc_clock_switching_example/
/usr/local/asf/sam/drivers/pmc/pmc_clock_failure_detect_example/
/usr/local/asf/sam/drivers/rtt/example/
/usr/local/asf/sam/drivers/pio/pio_capture_example/
/usr/local/asf/sam/drivers/acc/acc_example/
/usr/local/asf/sam/drivers/pdc/pdc_uart_example/
/usr/local/asf/sam/drivers/wdt/example/
/usr/local/asf/sam/drivers/dacc/sinewave_example/
/usr/local/asf/sam/drivers/adc/adc_threshold_wakeup_example/
/usr/local/asf/sam/drivers/adc/adc_temp_sensor_example/
/usr/local/asf/sam/drivers/adc/adc_example/
/usr/local/asf/sam/drivers/tc/tc_capture_waveform_example/
/usr/local/asf/sam/drivers/pwm/pwm_sync_example/
/usr/local/asf/sam/drivers/pwm/pwm_led_example/
/usr/local/asf/sam/drivers/spi/example/
/usr/local/asf/sam/drivers/spi/spi_pdc_example/
/usr/local/asf/sam/drivers/matrix/example/
/usr/local/asf/sam/components/display/ili9325/example/
/usr/local/asf/sam/services/flash_efc/flash_read_unique_id_example/
/usr/local/asf/sam/services/flash_efc/flash_program_example/
/usr/local/asf/sam/services/resistive_touch/example/
/usr/local/asf/sam/utils/cmsis/cm4_cmsis_example/
/usr/local/asf/sam/utils/cmsis/cm4_nvic_example/
/usr/local/asf/sam/utils/cmsis/cm4_bit_banding_example/
/usr/local/asf/thirdparty/lwip/netconn_http_stats_example/
/usr/local/asf/thirdparty/lwip/raw_http_basic_example/
/usr/local/asf/thirdparty/CMSIS/DSP_Lib/Examples/arm_sin_cos_example/
/usr/local/asf/thirdparty/CMSIS/DSP_Lib/Examples/arm_signal_converge_example/
/usr/local/asf/thirdparty/CMSIS/DSP_Lib/Examples/arm_fir_example/
/usr/local/asf/thirdparty/CMSIS/DSP_Lib/Examples/arm_class_marks_example/
/usr/local/asf/thirdparty/CMSIS/DSP_Lib/Examples/arm_convolution_example/
/usr/local/asf/thirdparty/CMSIS/DSP_Lib/Examples/arm_matrix_example/
/usr/local/asf/thirdparty/CMSIS/DSP_Lib/Examples/arm_dotproduct_example/
/usr/local/asf/thirdparty/CMSIS/DSP_Lib/Examples/arm_fft_bin_example/
/usr/local/asf/thirdparty/CMSIS/DSP_Lib/Examples/arm_graphic_equalizer_example/
/usr/local/asf/thirdparty/CMSIS/DSP_Lib/Examples/arm_variance_example/
/usr/local/asf/thirdparty/CMSIS/DSP_Lib/Examples/arm_linear_interp_example/
/usr/local/asf/thirdparty/fatfs/example/
/usr/local/asf/thirdparty/freertos/demo/sam_example/
/usr/local/asf/thirdparty/freertos/demo/peripheral_control/
/usr/local/asf/thirdparty/qtouch/generic/sam/qtouch/examples/
/usr/local/asf/common/components/memory/sd_mmc/
/usr/local/asf/common/components/memory/nand_flash/nand_flash_ebi/
/usr/local/asf/common/drivers/nvm/example/
/usr/local/asf/common/services/ioport/example3/
/usr/local/asf/common/services/usb/class/msc/device/example_freertos/
/usr/local/asf/common/services/usb/class/msc/device/example/
/usr/local/asf/common/services/usb/class/cdc/device/
/usr/local/asf/common/services/usb/class/phdc/device/example/
/usr/local/asf/common/services/usb/class/composite/device/
/usr/local/asf/common/services/usb/class/hid/device/generic/
/usr/local/asf/common/services/usb/class/hid/device/kbd/
/usr/local/asf/common/services/usb/class/hid/device/mouse/
/usr/local/asf/common/services/usb/class/vendor/device/example/
/usr/local/asf/common/services/clock/
/usr/local/asf/common/services/delay/
/usr/local/asf/common/services/spi/usart_spi_master_example/
int plus(int, int); // dans un prototype, il n'y a pas d'obligation à nommer les arguments
{}
de la fonction. On la place dans un fichier source (.c ou .cpp). Par exemple :
int plus(int a, int b) { return a + b ; }
#include "plus.h"
int res = plus(2, 2);
cible : dépendance(s)
<TAB>commande(s)
Le script run.sh
permet de flasher le programme sur la carte :
$ vim run.sh
#!/bin/bash
INTERFACE=jlink
BOARD=atmel_sam4s_ek
FORMAT="ELF 32-bit LSB executable"
OPENOCD=openocd
if [ $# -eq 1 ]
then
if !(test -f $1)
then
echo "Erreur fichier $1"
else
if [ ! -x "`which $OPENOCD 2>&-`" ]
then
echo "Erreur $OPENOCD absent"
else
file "$1" | grep -i "$FORMAT" > /dev/null 2>&1
if [ ${?} -eq "0" ]
then
$OPENOCD -f interface/$INTERFACE.cfg -f board/$BOARD.cfg -c init -c halt -c "flash write_image erase $1" -c reset -c shutdown
else
echo "Erreur format fichier $1"
fi
fi
fi
else
echo "Syntaxe : $(basename $0) fichier.elf"
echo ""
fi
Test :
$ ./run.sh
Syntaxe : run.sh fichier.elf
$ ./run.sh xxx_flash.elf
Rappel : Utileser la commande make clean
.
Le script clean.sh
permet de nettoyer le dossier de projet :
$ vim clean.sh
#!/bin/bash
rm -rf common/ sam/ thirdparty/
rm -f *.bin *.elf *.lss *.map *.sym *.hex *.o *.d *~
Le script openocd.sh
permet d’exécuter openocd en lui passant un fichier de configuration openocd.cfg
:
$ vim clean.sh
#!/bin/bash
FILE="./openocd.cfg"
OPENOCD=openocd
if [ ! -x "`which $OPENOCD 2>&-`" ]
then
echo "Erreur $OPENOCD absent"
else
if !(test -f "$FILE")
then
echo "Erreur fichier configuration $1"
else
$OPENOCD -f "$FILE"
fi
fi
Le fichier de configuration openocd.cfg
:
telnet_port 4444
gdb_port 3333
source [find interface/jlink.cfg]
source [find board/atmel_sam4s_ek.cfg]
gdb_flash_program enable