Le kit AT91SAM7L-STK rev.B dispose :
Cette carte est équipée d’un processeur 32-bits ARM7TDMI AT91SAM7L128.
Les caractéristiques de base sont :
Le port PIO d’extension :
Atmel SAM-ICE est un émulateur JTAG conçu pour les microcontrôleurs ARM Atmel SAMA5, SAM3, SAM4, SAM7 et SAM9. Alimenté par le port USB, il intégre un mode compatible J-Link et supporte GDB en mode serveur.
À savoir : Le JTAG (Joint Test Action Group) est le nom de la norme IEEE 1149.1 intitulée « Standard Test Access Port and Boundary-Scan Architecture ». La technique de Boundary-Scan a été conçue pour faciliter et automatiser le test des cartes électroniques numériques. Elle consiste à donner un accès auxiliaire aux broches d’entrée-sortie des composants numériques fortement intégrés. La norme JTAG est utilisée pour remplacer les émulateurs de microprocesseurs (systèmes de débug sur carte remplaçant physiquement le composant), en donnant un accès direct à l’intérieur du processeur (points d’arrêt, lecture et écriture des registres internes, des mémoires internes et externes …) sans perturber ses interactions avec l’extérieur. On nomme cette technique ICE (In-Circuit Emulator) ou ICD (In-Circuit Debugger), et elle est omniprésente sur les microprocesseurs et microcontrôleurs modernes. Le bus JTAG est également utilisé pour programmer de nombreux microcontrôleurs (grâce à la capacité du JTAG de programmer la mémoire Flash) et pour débugger un microprocesseur. Le bus JTAG est un bus série synchrone.
Sous Linux, SAM-ICE est pris en charge par OpenOCD (Open On-Chip Debugger) ou J-Link SEGGER (https://www.segger.com/jlink-software.html).
On aura besoin :
Télécharger le paquet DEB J-Link version 64 bits sur le site de SEGGER https://www.segger.com/jlink-software.html
Installer le paquet logiciel :
$ sudo dpkg -i jlink_5.12.7_x86_64.deb
$ JLinkGDBServer -if JTAG -device AT91SAM7L128
La procédure est décrite à cette adresse : http://gnuarmeclipse.github.io/toolchain/install/
$ sudo apt-get -y install lib32z1 lib32ncurses5 lib32bz2-1.0
$ sudo apt-get -y install ia32-libs
$ cd /usr/local
$ sudo wget -c https://launchpad.net/gcc-arm-embedded/5.0/5-2016-q1-update/+download/gcc-arm-none-eabi-5_3-2016q1-20160330-linux.tar.bz2
$ sudo tar xjf gcc-arm-none-eabi-5_3-2016q1-20160330-linux.tar.bz2
$ /usr/local/gcc-arm-none-eabi-5_3-2016q1/bin/arm-none-eabi-gcc -v
...
gcc version 5.3.1 20160307 (release) [ARM/embedded-5-branch revision 234589] (GNU Tools for ARM Embedded Processors)
$ /usr/local/gcc-arm-none-eabi-5_3-2016q1/bin/arm-none-eabi-gcc
arm-none-eabi-gcc: fatal error: no input files
compilation terminated.
La chaîne de compilation croisée est prête à l’emploi.
On aura besoin :
Remarque : Certains outils sont fournis avec le CD joint au kit.
Installer :
Remarque : j’ai démarré à partir d’un exemple fourni sur le CD qui correspond à la version 1.4 de l’API. Sinon la version 1.5 est disponible ici.
Codes sources :
Remarque : Les différents projets pour les deux systèmes Linux et Windows se distinguent seulement par leur Makekile et la façon de flasher le programme.
Mise en oeuvre du bus I2C/TWI :
I2C (Inter-Integrated Circuit) est un bus de données qui permet de relier facilement un microprocesseur et différents circuits électroniques. Conçu par Philips en 1982 pour les applications de domotique et d’électronique domestique, il a permis d’interconnecter les composants d’une télévision moderne : récepteur de la télécommande, réglages des amplificateurs basses fréquences, tuner, horloge, gestion de la prise péritel, etc.
Il existe maintenant d’innombrables périphériques exploitant ce bus, dont beaucoup de microcontrôleurs. Le poids de l’industrie de l’électronique grand public a permis des prix très bas grâce à ces nombreux composants.
Remarque : Ce bus porte parfois le nom de TWI (Two Wire Interface) chez certains constructeurs. C’est la cas ici avec Atmel.
I2C est un bus série synchrone bidirectionnel half-duplex. Le débit peut aller jusqu’à 400 Kbits/s (100 Kbits/s en mode standard).
Plusieurs équipements, soit maîtres, soit esclaves, peuvent être connectés au bus. Les échanges ont toujours lieu entre un seul maître et un (ou tous les) esclave(s), toujours à l’initiative du maître (jamais de maître à maître ou d’esclave à esclave). Cependant, rien n’empêche un composant de passer du statut de maître à esclave et réciproquement.
La connexion est réalisée par l’intermédiaire de deux lignes :
Remarque : Il ne faut également pas oublier la masse (GND) qui doit être commune aux équipements.
Le nombre maximal d’équipements est limité par le nombre d’adresses disponibles, 7 bits pour l’adresse et un bit pour définir si on écrit ou on lit (R/W), soit en théorie 128 périphériques. De nombreuses adresses sont déjà attribuées par les fabricants ce qui limite grandement le nombre d’équipements. Un mode d’adressage sur 10 bits existent mainteant.
On désire lire et/ou écrire une E/S numérique à partir d’un circuit I2C. On utilisera le circuit PCF8574 qui dispose de 8 E/S.
Documentation : PCF8574.pdf
Remarque : l’adresse de base du PCF8574 est 0x40 avec le bit R/W et 0x20 donc (0x40 >> 1) si le bit R/W (poids faible) n’intervient pas dans l’adresse du circuit I2C.
La carte AT91SAM7L-STK dispose d’un bus TWI :
On va donc utiliser le bus TWI avec les lignes PC11 (SCL) et PC10 (SDA) :
Remarque : les deux résistances de pull-up ne sont pas présentes sur la carte AT91SAM7L-STK.
//------------------------------------------------------------------------------
// Headers
//------------------------------------------------------------------------------
#include <board.h>
#include <pit/pit.h>
#include <slcdc/slcdc.h>
#include <supc/supc.h>
#include <pio/pio.h>
#include <aic/aic.h>
#include <tc/tc.h>
#include <slcd/s7lstklcd/s7lstklcd.h>
#include <pio/pio_it.h>
#include <dbgu/dbgu.h>
#include <twi/twi.h>
#include <utility/math.h>
#include <utility/assert.h>
#include <utility/trace.h>
#include <drivers/twi/twid.h>
#include <stdio.h>
#include <string.h>
//------------------------------------------------------------------------------
// Local definitions
//------------------------------------------------------------------------------
/// Softpack Version
#define SOFTPACK_VERSION "1.4"
/// Scrolling frequency in Hz.
#define SCROLLING_FREQUENCY 8
/// String is scrolling to the left
#define SCROLL_LEFT 0
/// String is scrolling to the right
#define SCROLL_RIGHT 1
#define LCD_OFF 0
#define LCD_ON 1
/// Master clock frequency in Hz
#define MCK 32768
/// TWI clock frequency in Hz.
#define TWCK 400000
/// Slave address of AT24C chips.
#define I2C_ADDRESS 0x20
//------------------------------------------------------------------------------
// Local variables
//------------------------------------------------------------------------------
/// Pins to configure for the application
static const Pin pPins[] = {BOARD_MAX3318E_ENABLE_FORCEOFF, BOARD_MAX3318E_DISABLE_PULLUPS};
/// Pushbutton pin instance.
const Pin pinPB1 = PIN_PUSHBUTTON_1; // CENTRE
const Pin pinPB2 = PIN_PUSHBUTTON_2; // HAUT
const Pin pinPB3 = PIN_PUSHBUTTON_3; // DROITE
const Pin pinPB4 = PIN_PUSHBUTTON_4; // BAS
const Pin pinPB5 = PIN_PUSHBUTTON_5; // GAUCHE
static unsigned char lcdScreen = LCD_ON;
/// Pio pins to configure.
static const Pin pinsTWI[] = {PINS_TWI};
/// TWI driver instance.
static Twid twid;
/// TWI buffer.
static unsigned char pData[1];
//------------------------------------------------------------------------------
// Local functions
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
/// TWI interrupt handler. Forwards the interrupt to the TWI driver handler.
//------------------------------------------------------------------------------
void ISR_Twi(void)
{
TWID_Handler(&twid);
}
//------------------------------------------------------------------------------
/// Configures TWI.
//------------------------------------------------------------------------------
static void ConfigureTWI(void)
{
PIO_Configure(pinsTWI, PIO_LISTSIZE(pinsTWI));
// Configure TWI
// In IRQ mode: to avoid problems, the priority of the TWI IRQ must be max.
// In polling mode: try to disable all IRQs if possible.
// (in this example it does not matter, there is only the TWI IRQ active)
AT91C_BASE_PMC->PMC_PCER = 1 << AT91C_ID_TWI;
TWI_ConfigureMaster(AT91C_BASE_TWI, TWCK, BOARD_MCK);
TWID_Initialize(&twid, AT91C_BASE_TWI);
AIC_ConfigureIT(AT91C_ID_TWI, 0, ISR_Twi);
AIC_EnableIT(AT91C_ID_TWI);
memset(pData, 0, 1);
}
//------------------------------------------------------------------------------
/// Initializes the SLCD controller with the board parameters.
//------------------------------------------------------------------------------
static void InitializeSlcd(void)
{
// Enable SLCD internal power supply (3V)
SUPC_EnableSlcd(AT91C_SUPC_LCDMODE_INTERNAL);
SUPC_SetSlcdVoltage(0x9);
// Disable SLCD
SLCDC_Disable();
// Define the number of COM and SEG, Buffer driving time; select the bias
SLCDC_Configure(S7LSTKLCD_NUM_COMMONS,
S7LSTKLCD_NUM_SEGMENTS,
AT91C_SLCDC_BIAS_1_3,
AT91C_SLCDC_BUFTIME_0_percent);
// Set frame rate 30 Hz
SLCDC_SetFrameFreq(AT91C_SLCDC_PRESC_SCLK_32, AT91C_SLCDC_DIV_2);
// Enable SLCD
SLCDC_Enable();
}
//------------------------------------------------------------------------------
/// Interrupt service routine for the Timer Counter 0. Makes the displayed
/// string scroll from left to right.
//------------------------------------------------------------------------------
static void ISR_Tc0(void)
{
static unsigned char lastData = 0x00;
TWID_Read(&twid, I2C_ADDRESS, 0, 0, pData, 1, 0);
if(pData[0] != lastData)
{
printf("pData[0] = 0x%02X\r\n", pData[0]);
lastData = pData[0];
}
}
//------------------------------------------------------------------------------
/// Interrupt handler for pushbutton\#1.
//------------------------------------------------------------------------------
static void ISR_Bp1(void)
{
// Check if the button has been pressed
if (!PIO_Get(&pinPB1))
{
printf("Bp1 ");
memset(pData, 0, 1);
pData[0] = 0x01;
TWID_Write(&twid, I2C_ADDRESS, 0, 0, pData, 1, 0);
SLCDC_Clear();
S7LSTKLCD_String(0, 1, "Bp 1");
SLCDC_SetDisplayMode(AT91C_SLCDC_DISPMODE_NORMAL);
}
}
//------------------------------------------------------------------------------
/// Interrupt handler for pushbutton\#2.
//------------------------------------------------------------------------------
static void ISR_Bp2(void)
{
// Check if the button has been pressed
if (!PIO_Get(&pinPB2))
{
printf("Bp2 ");
memset(pData, 0, 1);
pData[0] = 1 << 1;
TWID_Write(&twid, I2C_ADDRESS, 0, 0, pData, 1, 0);
SLCDC_Clear();
S7LSTKLCD_String(0, 1, "Bp 2");
SLCDC_SetDisplayMode(AT91C_SLCDC_DISPMODE_NORMAL);
}
}
//------------------------------------------------------------------------------
/// Interrupt handler for pushbutton\#3.
//------------------------------------------------------------------------------
static void ISR_Bp3(void)
{
// Check if the button has been pressed
if (!PIO_Get(&pinPB3))
{
printf("Bp3 ");
memset(pData, 0, 1);
pData[0] = 1 << 2;
TWID_Write(&twid, I2C_ADDRESS, 0, 0, pData, 1, 0);
SLCDC_Clear();
S7LSTKLCD_String(0, 1, "Bp 3");
SLCDC_SetDisplayMode(AT91C_SLCDC_DISPMODE_NORMAL);
}
}
//------------------------------------------------------------------------------
/// Interrupt handler for pushbutton\#4.
//------------------------------------------------------------------------------
static void ISR_Bp4(void)
{
// Check if the button has been pressed
if (!PIO_Get(&pinPB4))
{
printf("Bp4 ");
memset(pData, 0, 1);
pData[0] = 1 << 3;
TWID_Write(&twid, I2C_ADDRESS, 0, 0, pData, 1, 0);
SLCDC_Clear();
S7LSTKLCD_String(0, 1, "Bp 4");
SLCDC_SetDisplayMode(AT91C_SLCDC_DISPMODE_NORMAL);
}
}
//------------------------------------------------------------------------------
/// Interrupt handler for pushbutton\#5.
//------------------------------------------------------------------------------
static void ISR_Bp5(void)
{
// Check if the button has been pressed
if (!PIO_Get(&pinPB5))
{
printf("Bp5 ");
memset(pData, 0, 1);
pData[0] = 1 << 4;
TWID_Write(&twid, I2C_ADDRESS, 0, 0, pData, 1, 0);
SLCDC_Clear();
S7LSTKLCD_String(0, 1, "Bp 5");
SLCDC_SetDisplayMode(AT91C_SLCDC_DISPMODE_NORMAL);
}
}
//------------------------------------------------------------------------------
/// Configures the pushbuttons to generate interrupts when pressed.
//------------------------------------------------------------------------------
static void ConfigureButtons(void)
{
// Configure pios
PIO_Configure(&pinPB1, 1);
PIO_Configure(&pinPB2, 1);
PIO_Configure(&pinPB3, 1);
PIO_Configure(&pinPB4, 1);
PIO_Configure(&pinPB5, 1);
// Initialize interrupts
PIO_InitializeInterrupts(AT91C_AIC_PRIOR_LOWEST);
PIO_ConfigureIt(&pinPB1, (void (*)(const Pin *)) ISR_Bp1);
PIO_ConfigureIt(&pinPB2, (void (*)(const Pin *)) ISR_Bp2);
PIO_ConfigureIt(&pinPB3, (void (*)(const Pin *)) ISR_Bp3);
PIO_ConfigureIt(&pinPB4, (void (*)(const Pin *)) ISR_Bp4);
PIO_ConfigureIt(&pinPB5, (void (*)(const Pin *)) ISR_Bp5);
PIO_EnableIt(&pinPB1);
PIO_EnableIt(&pinPB2);
PIO_EnableIt(&pinPB3);
PIO_EnableIt(&pinPB4);
PIO_EnableIt(&pinPB5);
}
//------------------------------------------------------------------------------
/// Main function
//------------------------------------------------------------------------------
int main(void)
{
unsigned int div, tcclks;
// DBGU configuration
trace_CONFIGURE(DBGU_STANDARD, 115200, BOARD_MCK);
/*const Pin pinsDbgu[] = {PINS_DBGU};
PIO_Configure(pinsDbgu, PIO_LISTSIZE(pinsDbgu));
DBGU_Configure(DBGU_STANDARD, 115200, BOARD_MCK);*/
printf("-- Getting Started Project %s --\n\r", SOFTPACK_VERSION);
printf("-- %s\n\r", BOARD_NAME);
printf("-- Compiled: %s %s --\n\r", __DATE__, __TIME__);
printf("Start I2C 0x%02X\n\r", I2C_ADDRESS);
ConfigureTWI();
ConfigureButtons();
//PIO_Configure(pPins, PIO_LISTSIZE(pPins));
// Initialize SLCD
InitializeSlcd();
SLCDC_Clear();
S7LSTKLCD_String(0, 1, "I2C");
SLCDC_SetDisplayMode(AT91C_SLCDC_DISPMODE_NORMAL);
// Configure timer for interrupt every 250ms
AT91C_BASE_PMC->PMC_PCER |= 1 << AT91C_ID_TC0;
TC_FindMckDivisor(SCROLLING_FREQUENCY, MCK, &div, &tcclks);
TC_Configure(AT91C_BASE_TC0, tcclks | AT91C_TC_CPCTRG);
AT91C_BASE_TC0->TC_RC = (MCK / div) / SCROLLING_FREQUENCY;
AIC_ConfigureIT(AT91C_ID_TC0, 0, ISR_Tc0);
AIC_EnableIT(AT91C_ID_TC0);
AT91C_BASE_TC0->TC_IER = AT91C_TC_CPCS;
TC_Start(AT91C_BASE_TC0);
// Test
/*memset(pData, 0, 1);
pData[0] = 0x55;
TWID_Write(&twid, I2C_ADDRESS, 0, 0, pData, 1, 0);
// Wait at least 10 ms
unsigned int i = 0;
for (i=0; i < 1000000; i++);
printf("Read I2C 0x%02X\n\r", I2C_ADDRESS);
// Read back data
memset(pData, 0, 1);
TWID_Read(&twid, I2C_ADDRESS, 0, 0, pData, 1, 0);
printf("pData[0] = 0x%02X\r\n", pData[0]);*/
// Infinite loop
while(1);
}
$ unzip slcd-bp-project-1.4-at91sam7l-stk-linux.zip
$ cd slcd-bp-project-1.4-at91sam7l-stk-linux/slcd-bp-project
$ make
$ cd bin
$ JLinkExe -if JTAG -device AT91SAM7L128 -speed 5000
SEGGER J-Link Commander V5.12g (Compiled May 27 2016 17:03:43)
DLL version V5.12g, compiled May 27 2016 17:03:38
Connecting to J-Link via USB...O.K.
Firmware: J-Link ARM V8 compiled Aug 26 2015 15:08:21
Hardware version: V8.00
S/N: 28010360
License(s): RDI
OEM: SAM-ICE
VTref = 2.698V
J-Link>loadbin slcd-bp-at91sam7l-stk-at91sam7l128-flash.bin 0x00100000
Target connection not established yet but required for command.
Device position in JTAG chain (IRPre,DRPre) <Default>: -1,-1 => Auto-detect
JTAGConf>connect
ERROR while parsing value for IRPre. Using default: -1.
ERROR while parsing value for DRPre. Using default: -1.
Device "AT91SAM7L128" selected.
TotalIRLen = 4, IRPrint = 0x01
Found 1 JTAG device, Total IRLen = 4:
#0 Id: 0x3F0F0F0F, IRLen: 04, IRPrint: 0x1, ARM7TDMI Core
ARM7 identified.
Downloading file [slcd-bp-at91sam7l-stk-at91sam7l128-flash.bin]...
**************************
WARNING: CPU is running at low speed (1872 kHz).
**************************
Comparing flash [100%] Done.
Erasing flash [100%] Done.
Programming flash [100%] Done.
Verifying flash [100%] Done.
J-Link: Flash download: Flash programming performed for 2 ranges (15196 bytes)
J-Link: Flash download: Total time needed: 1.211s (Prepare: 0.038s, Compare: 0.226s, Erase: 0.000s, Program: 0.763s, Verify: 0.178s, Restore: 0.005s)
O.K.
J-Link>r
Reset delay: 0 ms
Reset type NORMAL: Using RESET pin, halting CPU after Reset
J-Link>exit
Appuyez sur le bouton Reset (off) puis sur le bouton WakeUP (on).
Remarque : vous pouvez utiliser un script pour automatiser le flashage et le lancement du rogramme (cf. Annexe n°1 et 2)
Décompresser l’archive slcd-bp-project-1.4-at91sam7l-stk-windows.zip
Lancer cmd.exe
Se déplacer dans le dossier slcd-bp-project-1.4-at91sam7l-stk-windows/slcd-bp-project
Taper make
(ou mingw32-make
)
Lancer Sam-ba
Choisir le fichier slcd-bp-at91sam7l-stk-at91sam7l128-flash.bin
puis cliquer sur Send File (Répondre Non ensuite)
Cliquer sur Execute après avoir sélectionner Boot from Flash
Quitter Sam-ba et Appuyer sur le bouton Reset (off) puis sur le bouton WakeUP (on).
Embedded Studio est un EDI (Environnement de Développement Intégré ou IDE pour Integrated Development Environment) C/C++ pour les microcontrôleurs ARM.
cible : dépendance(s)
<TAB>commande(s)
Le niveau (« HIGH » ou « LOW ») de la ligne SDA doit être maintenu stable pendant le niveau « HIGH » sur la ligne SCL pour la lecture du bit.
Il existe cinq vitesses de transmission :
Le bus étant synchrone, c’est le maître qui impose l’horloge via la ligne SCL.
La condition de START est une transgression de la règle de codage des bits qui est utilisée par le maître pour signifier le début d’une trame. Cette condition est caractérisée par le passage de la ligne SDA du niveau « HIGH » au niveau « LOW » pendant que la ligne « SCL » est maintenue au niveau « HIGH ».
La condition de STOP est une transgression de la règle de codage des bits qui est utilisée par le maître pour signifier la fin d’une trame. Cette condition est caractérisée par le passage de la ligne SDA du niveau « LOW » au niveau « HIGH » pendant que la ligne SCL est maintenue au niveau « HIGH ».
Le récepteur positionne le bit d’acquittement à :
On peut également considérer que l’adresse est codée sur les 8 bits, chaque esclave a alors deux adresses, l’adresse paire qui sert à lui envoyer des données, l’adresse impaire pour lui demander d’en envoyer.
Généralement, les fabricants des circuits I2C fixent une partie de l’adresse pour permettre d’identifier le type de circuit et laissent une partie libre permettant de relier plusieurs circuits du même type sur le bus.
Par exemple, le circuit I2C de 8 bits E/S (I/O) est déclinée en deux versions donnant deux adresses de base :
Le fabricant a laissé libre les 3 bits d’adresses de poids faible (A2 A1 A0) ce qui permettra de relier 2^3 = 8 circuits sur un même bus.
Le script run.sh
permet de flasher le programme sur la carte :
$ vim run.sh
#!/bin/bash
JLINK=JLinkExe
DEVICE=AT91SAM7L128
SPEED=5000
FORMAT="data"
if [ $# -eq 1 ]
then
if !(test -f bin/$1)
then
echo "Erreur fichier $1"
else
if [ ! -x "`which $JLINK 2>&-`" ]
then
echo "Erreur $JLINK absent"
else
file "bin/$1" | grep -i "$FORMAT" > /dev/null 2>&1
if [ ${?} -eq "0" ]
then
$JLINK -if JTAG -device $DEVICE -speed auto -jtagconf -1,-1 -autoconnect 1 -CommanderScript jlink.cfg
else
echo "Erreur format fichier $1"
fi
fi
fi
else
echo "Syntaxe : $(basename $0) fichier.bin"
echo ""
fi
Test :
$ ./run.sh
Syntaxe : run.sh fichier.bin
$ ./run.sh slcd-twi-at91sam7l-stk-at91sam7l128-flash.bin
Le fichier de configuration jlink.cfg
:
r
h
loadbin ./bin/slcd-twi-at91sam7l-stk-at91sam7l128-flash.bin,0x00100000
r
g
qc