Stellaris Luminary Lm3s6965: Difference between revisions

From air
Jump to navigation Jump to search
No edit summary
(Ajout de la Documentaion réalisée et des modifications)
 
(35 intermediate revisions by 2 users not shown)
Line 2: Line 2:


[[File:EKI-LM3S6965.jpg|200px|thumb|right| Stellaris Luminary Lm3s6965 ]]
[[File:EKI-LM3S6965.jpg|200px|thumb|right| Stellaris Luminary Lm3s6965 ]]
Ce [http://www.luminarymicro.com/products/lm3s6965_ethernet_evaluation_kit.html kit] est contruit autour d'un microcontrolleur [[ARM Cortex-M3]] Lm3s6965
Ce [http://www.luminarymicro.com/products/lm3s6965_ethernet_evaluation_kit.html kit] est construit autour d'un microcontrolleur [[ARM Cortex-M3]] Lm3s6965
de marque Luminary Micro appartenant au groupe Texas Instrument.
de marque Luminary Micro appartenant au groupe Texas Instrument.


Les principales caratéristiques et intérêt de ce kit sont:
Les principales caratéristiques et intérêts de ce kit sont:


* Processeur ARM 32bit Cortex-M3
* Processeur ARM 32bit Cortex-M3
Line 14: Line 14:




==Ressources==
=Ressources=
* Site officiel du [http://www.luminarymicro.com/products/lm3s6965_ethernet_evaluation_kit.html kit Stellaris Luminary Lm3s6965]
* Site officiel du [http://www.luminarymicro.com/products/lm3s6965_ethernet_evaluation_kit.html kit Stellaris Luminary Lm3s6965]


Line 25: Line 25:
* ARM Projets divers : [http://gandalf.arubi.uni-kl.de/avr_projects/arm_projects/]
* ARM Projets divers : [http://gandalf.arubi.uni-kl.de/avr_projects/arm_projects/]


* Tutorial général: [[Media:Tuto_lm3s6965.pdf]]
== Exemples d'utilisation ==


* Le document technique (datasheet) du microcontrolleur Lm3s6965: [[Media:Datasheet-LM3S6965.pdf‎]]


= Exemples d'utilisation =
=== Utilisation avec OpenOCD sous linux ===

Les exemples ci-dessus rassemblent un ensemble d'outils et de codes complétant ceux proposé par le constructeur dans une vision opensource.
Une image virtuelle est aussi fournie, voir ci-dessous.

=Debut avec la Carte Stellaris=

Pour programmer la carte, il faut tout d'abord installer la chaîne de compilation.

== Compilation du toolchain ==

Suivre [http://www.codesourcery.com/sgpp/lite/arm/portal/package7815/public/arm-none-eabi/arm-2010.09-51-arm-none-eabi.bin Binaire Linux] pour récupérer la chaîne de compilation Sourcery G++ Lite.<br>
D'autres paquets disponibles sur le [http://www.codesourcery.com/sgpp/lite/arm/portal/release1592 site du logiciel]


== Compilation des exemples ==

Une fois le toolchain installé, il est intéressant de regarder les fichiers de tests disponible sur le CD d'Installation. L'éxecutable SW-EK-LM3S6965.exe propose un grand nombre de test recompilable à l'aide des fichiers adjacents. Ces codes étant fournis par le constructeur, ce sont eux qui vont valider la bonne émulation de la carte.


== Compilation d'exemples plus simples ==

Les fichiers test-cortex-m3.c, startup_gcc.c et lm3s.ld utilisés ci-aprés sont disponibles dans l'archive: [[Media:Test-cortex-m3.tar]]

Construction de l'exécutable

arm-none-eabi-gcc -c -mcpu=cortex-m3 -mthumb test-cortex-m3.c -o test-cortex-m3.o
arm-none-eabi-gcc -c -mcpu=cortex-m3 -mthumb startup_gcc.c -o startup_gcc.o
arm-none-eabi-ld -T lm3s.ld startup_gcc.o test-cortex-m3.o -o test-cortex-m3.elf
arm-none-eabi-nm test-cortex-m3.elf


Juste pour voir le code déassemblé
arm-none-eabi-objdump -d test-cortex-m3.elf


Il faut une version binaire simple à charger et non la version trop riche
arm-none-eabi-objcopy -O binary test-cortex-m3.elf test-cortex-m3.bin

Le binaire peut ensuite être placé(flashé) sur la carte avec OpenOCD ou utilisé avec l'émulateur QEMU, voir ci-dessous.


== Chargement du bin sur la carte ==

=== Utilisation avec [[OpenOCD]] sous linux ===


Récupérer le script ''setup_lm3s6965.sh'' sur [http://claymore.engineer.gvsu.edu/egr326/LM3S6965].
Récupérer le script ''setup_lm3s6965.sh'' sur [http://claymore.engineer.gvsu.edu/egr326/LM3S6965].
Ce script va récupérer et compiler openocd.
Ce script va récupérer et compiler openocd. Une copie est disponible [[Media:Setup_lm3s6965.txt]]


<pre>sh setup_lm3s6965.txt</pre>
./setup_lm3s6965.sh


Construire et installer le bon pilote FTDI
Construire et installer le bon pilote FTDI


<pre>
wget http://www.intra2net.com/en/developer/libftdi/download/libftdi-0.18.tar.gz
wget http://www.intra2net.com/en/developer/libftdi/download/libftdi-0.18.tar.gz
#install open FTDI drivers
#install open FTDI drivers
Line 46: Line 92:
sudo make install
sudo make install
sudo ldconfig
sudo ldconfig
</pre>


On lance openocd en root
On lance openocd en root


sudo openocd -f /usr/local/share/openocd/scripts/board/ek-lm3s6965.cfg
<pre>sudo openocd -f /usr/local/share/openocd/scripts/board/ek-lm3s6965.cfg</pre>

Et on peut flash la microntrolleur


Et on peut flash le microcontrolleur
<pre>
#flash mcu with some code at address 0x00000 and execute
#flash mcu with some code at address 0x00000 and execute
telnet localhost 4444
telnet localhost 4444
Line 58: Line 105:
flash write_image erase /tmp/main.bin 0
flash write_image erase /tmp/main.bin 0
reset
reset
</pre>



Exemple avec le déboggeur gdb
Exemple avec le déboggeur gdb


=== qemu ===




= Debut avec [[Qemu | QEMU]] =
Les fichiers test-cortex-m3.c, startup_gcc.c et lm3s.ld utilisé ci-aprés sont disponible dans l'archive: [[File:Test-cortex-m3.tar]]


== Compilation et première utilisation ==


Récupération et compilation du qemu version qemu-0.13.0
Construction de l'exécutable
wget http://wiki.qemu.org/download/qemu-0.13.0.tar.gz
tar zxvf qemu-0.13.0.tar.gz
cd qemu-0.13.0
./configure --target-list=arm-softmmu # On configure pour ne pas tout compiler
make


'''Note''' : La version qemu-0.14.0 a été réalisée le 18/02/11
arm-none-eabi-gcc -c -mcpu=cortex-m3 -mthumb test-cortex-m3.c -o test-cortex-m3.o
arm-none-eabi-gcc -c -mcpu=cortex-m3 -mthumb startup_gcc.c -o startup_gcc.o
arm-none-eabi-ld -T lm3s.ld startup_gcc.o test-cortex-m3.o -o test-cortex-m3.elf
arm-none-eabi-nm test-cortex-m3.elf


Lancement de l'émulation avec qemu (faire '''crtl a + x''' pour sortir ou '''crtl a + c''' pour accéder au moniteur)
Juste de pour voir le code déassemblé
arm-none-eabi-objdump -d test-cortex-m3.elf

Il faut une version binaire simple à charger et non la version trop riche
arm-none-eabi-objcopy -O binary test-cortex-m3.elf test-cortex-m3.bin


Lancement de l'émulation avec qemu
./qemu-0.13.0/arm-softmmu/qemu-system-arm -M lm3s6965evb -nographic -kernel test-cortex-m3.bin
./qemu-0.13.0/arm-softmmu/qemu-system-arm -M lm3s6965evb -nographic -kernel test-cortex-m3.bin
Hello world!
Hello world!
Line 88: Line 130:
(qemu) quit
(qemu) quit


== FAQ ==


== Moniteur (console de commande et d'interrogation de Qemu) ==
==Ressources==
Qemu dispose d'un moniteur assez puissant. Utilisez l'option '''-S''' pour lancer le moniteur dès le démarrage l'émulation sera alors suspendu, puis faire '''crtl+a c''' pour accèder à la console d moniteur

./qemu-0.13.0/arm-softmmu/qemu-system-arm -S -M lm3s6965evb -nographic -kernel test-cortex-m3.bin
'''crtl+a c'''

(qemu) info roms
addr=00000000 size=0x0001e0 mem=rom name="test-cortex-m3.bin"
(qemu) info registers
R00=000001d0 R01=20000000 R02=0000000a R03=00000000
R04=00000000 R05=00000000 R06=00000000 R07=2000fff0
R08=00000000 R09=00000000 R10=00000000 R11=00000000
R12=00000000 R13=2000fff0 R14=000001c9 R15=00000160
PSR=60000173 -ZC- T svc32

Malheureusement pour une émulation des cpus cortex-M3, l'ensemble des fonctions du moniteur ne sont pas toutes supportées. Par exemple le déassembleur intégré ne décode pas correctement les instructions. Pour aller plus loin, il faut utiliser le déboggeur cf suite.

== Qemu et GDB ==
On peut attaché GDB à Qemu

./qemu/qemu-0.13.0/arm-softmmu/qemu-system-arm -M lm3s6965evb -nographic -monitor null -serial null -semihosting -kernel /tmp/hello.bin -S -gdb tcp::51234

arm-none-eabi-gdb /tmp/hello.axf

(gdb) '''target remote localhost:51234'''
...
(gdb) '''load'''
(gdb) '''break main'''
(gdb) '''continue'''
Continuing.
Breakpoint 1, 0x000000f4 in main ()
(gdb) stepi
0x00000640 in SysCtlClockSet ()
(gdb) '''disassemble 0x640'''
Dump of assembler code for function SysCtlClockSet:
0x00000640 <SysCtlClockSet+0>: ldr r3, [pc, #308] ; (0x778 <SysCtlClockSet+312>)
0x00000642 <SysCtlClockSet+2>: push {r4, r5, r6, lr}
0x00000644 <SysCtlClockSet+4>: ldr r2, [r3, #0]
....

On peut attaché GDB à Qemu
http://cgi.cs.indiana.edu/~geobrown/stm32/Main/Simulation
http://garden.seeedstudio.com/index.php?title=DSO_Nano/Qemu_gdb&redirect=no



=Modifications réalisées sur QEMU=

== Suivi et accès des GPIO en sortie ==

Le principe va être d'utiliser le code élémentaire de clignotement de LED blinky.bin disponible dans le répertoire StellarisWare puis de modifier le fichier stellaris.c dans repertoire hw de qemu pour repérer et intercepter les changement d'état


Comprendre l'émulation du stellaris proposé par QEMU suppose de se plonger dans le code. On peut notamment explorer les fichiers suivant, liste non exhaustive:

hw/irq.c hw/qdev.c hw/stellaris.c hw/stellaris_input.c hw/sysbus.h
hw/irq.h hw/qdev.h hw/stellaris_enet.c hw/sysbus.c qemu-common.h


Il est important d'observer la struct '''qemu_irq'''. Dans le stellaris.c nous notons la déclaration suivante

static void stellaris_init(const char *kernel_filename, const char *cpu_model,
stellaris_board_info *board)
{
static const int uart_irq[] = {5, 6, 33, 34};
static const int timer_irq[] = {19, 21, 23, 35};
static const uint32_t gpio_addr[7] =
{ 0x40004000, 0x40005000, 0x40006000, 0x40007000,
0x40024000, 0x40025000, 0x40026000};
static const int gpio_irq[7] = {0, 1, 2, 3, 4, 30, 31};

qemu_irq *pic;
DeviceState *gpio_dev[7];
qemu_irq gpio_in[7][8];
qemu_irq gpio_out[7][8];

La déclaration qemu_irq gpio_out[7][8]; va permettre l'émulation des 8 fils de sortie des 7 port d'E/S (A,B,C,D,E,F,G).

Si on suit '''qemu_irq'' à travers les fichiers, nous avons:

Dans qemu-common.h qemu_irq est un pointer sur IRQState

typedef struct IRQState *qemu_irq;

IRQState dans hw/irq.c

struct IRQState {
qemu_irq_handler handler;
void *opaque;
int n;
};

Dans hw/irq.h:
typedef void (*qemu_irq_handler)(void *opaque, int n, int level);

qemu_irq_handler est un pointeur sur une fonction qui sera appelée lorsque ''le fils'' changera de valeur, voir la fonction qemu_set_irq dans irq.c:

void qemu_set_irq(qemu_irq irq, int level)
{
if (!irq)
return;

irq->handler(irq->opaque, irq->n, level);
}

On va maintenant maintenant de modifier le fichier stellaris.c pour suivre ''' l'état du bit 0 du port F en sortie ''' lequel est cablé un LED sur la carte physique (utilisé par le code blinky.bin).

static void print_yop(void *opaque, int line, int level)
{
/* opaque is null, can by use to access to a global state ??? */
printf("poy line %d level %d\n",line,level);
}

qemu_irq yop; /*test*/
yop = qemu_allocate_irqs(print_yop, NULL, 1)[0]; /* on alloue de ma mémoire et on positionne le handler, ici print_yop*/

gpio_out[GPIO_F][0] = yop; /* /!\ à faire après l'intialisation de tous les gpio_out, si il y a écrassement */

Archive contenant le fichier modifié stellaris.c et le code de clignotement de LED blinky.bin [[Media:stellaris_mod_blinky.tar]]

./qemu-0.13.0/arm-softmmu/qemu-system-arm -M lm3s6965evb -nographic -kernel blinky.bin

poy line 0 level 1
poy line 0 level 0
poy line 0 level 1
poy line 0 level 0
poy line 0 level 1
poy line 0 level 0

'''Note''' Ctrl A puis x quitter QEMU, voir les commandes du moniteur pour plus de détail.


==Affichage de Caractères sur l'OLED==

=== Ajout d'un registre d'horloge ===
Les programmes de test de l'OLED fournis ne fonctionnent pas en tant que tels. Qemu affiche une erreur dès le début de l'exécution.
Après des recherches dans le code des fonctions utilisées dans les exemples. Il vient qu'il est nécessaire de modifier les fonctions ssys_read et ssys_write de stellaris.c en ajoutant un cas supplémentaire.
<pre>
case 0x070: /* RCC2 */
return s->rcc2;
</pre>
et
<pre>
case 0x070 : /* RCC2 */
//p95 datasheet Register 10: Run-Mode Clock Configuration 2
if(value >> 31 != 0 ){ // if the USERCC2 bit is to 1 we
s->rcc=value; // override RCC;
}
if ((s->rcc2 & (1 << 13)) != 0 && (value & (1 << 13)) == 0) {
/* PLL enable. */
s->int_status |= (1 << 6);
}
s->rcc2 = value;
break;
</pre>
Le champs rcc2 de la structure s a été ajouté également. Ce champ correspond au registre Run-Mode Clock Configuration 2 (RCC2) décrit dans le datasheet.

=== Ajout d'un registre déprécié ===
'''Rédaction en Cours'''



= Documentation =
Une documentation sommaire a été réalisée afin que les personnes continuant le projet puisse comprendre ce qui a déjà été fait. Elle contient également quelques explications de la structure de Qemu et les fonctions. Le code n'étant pas très commenté, il est difficile à appréhender.


== Présentation Générale==

Ce texte présente brievement comment marche globalement l'émulation de la carte
Stellaris et quelques points importants pour comprendre le fonctionnement.

De la documentation spécifique à certains fichier est disponible.
Elle est plutot sommaire la plupart du temps mais permet d'appréhender mieux le
système.

La majeur partie de l'émulation de la carte Stellaris est réalisée dans le
fichier stellaris.c du dossier hw de Qemu.
On peut trouver dans ce fichier la déclaration de plusieurs structures correpondant
au convertisseur analogique numérique (adc), ssi, timer (gptm) et i2c.
Ensuite, on trouve les fonctions de lecture et d'ecriture dans les registres systemes.
Les 29 Registres systemes sont décrit dans le DataSheet de Stellaris.
(Attention, certains commentaires de code redirige vers un Datasheet plus ancien
que celui qu'on peut trouver sur le site du constructeur)

Stellaris utilise également des éléments extérieurs pour fonctionner.
L'OLED fait parti de ces éléments, étant donné qu'il peut être utilisé dans d'autres
carte.


Pour comprendre comment est émulé la carte, il est important de partir des tests
de base proposés sur le CD de Stellaris. Les bin donnés en paramètres de qemu
"simulent" déjà une partie du code donné.
Par exemple : le fichier hello.c appelle la fonction RIT128x96x4StringDraw avec
le paramètre "Hello World!". La compilation du programme va "déjà" modifier le paramètre
entré pour le mettre sous la forme de donnée en hexadécimal transmises à l'OLED.
C'est logique, étant donné que les bin seront éxécutés aussi sur la carte.


Cependant la compréhension de ce code est indispensable pour pouvoir ajouter des
fonctionnalités à qemu. Il faut savoir quelles sont les infos contenues dans le bin
afin de pouvoir les traiter et simuler le comportement réél.
Exemple pour une fonction largement répandue dans les fichiers de test :
<pre> Decomposition de l'exécution de l'appel à SysCtlClockSet (fichier sysctl.c)

Sortie console :

//Debut Qemu
Trying to read at offset : 0x0 //Printf ajoutés dans ssys_read
Trying to read at offset : 0x0

Début fonction : l 1367
Ne rentre pas dans le if du début :
CLASS_IS_SANDSTORM && (ulConfig & SYSCTL_RCC2_USERCC2)

Lecture de RCC et RCC2 : l 1389
Trying to read at offset : 0x60 ulRCC = HWREG(SYSCTL_RCC);
Trying to read at offset : 0x70 ulRCC2 = HWREG(SYSCTL_RCC2);

Calculs...

Ecriture de RCC et RCC2 : l 1402
Trying to write 0x78e3ac0 at offset : 0x60 HWREG(SYSCTL_RCC) = ulRCC;
Trying to write 0x800 at offset : 0x70 HWREG(SYSCTL_RCC2) = ulRCC2;


N'entre pas dans le if :
(((ulRCC & SYSCTL_RCC_IOSCDIS) && !(ulConfig & SYSCTL_RCC_IOSCDIS)) ||
((ulRCC & SYSCTL_RCC_MOSCDIS) && !(ulConfig & SYSCTL_RCC_MOSCDIS)))
L'oscillateur n'a pas besoin d'être activé
Calculs...


Ecriture MISC : l 1468
// Clear the PLL lock interrupt
HWREG(SYSCTL_MISC) = SYSCTL_INT_PLL_LOCK;
Trying to write 0x40 at offset : 0x58


Passe dans le else : !ulRCC2 & SYSCTL_RCC2_USERCC2
Ecriture de RCC et RCC2 : l 1480
Trying to write 0x78e3b80 at offset : 0x60 HWREG(SYSCTL_RCC) = ulRCC;
Trying to write 0x2800 at offset : 0x70 HWREG(SYSCTL_RCC2) = ulRCC2;


Ecriture de RCC et RCC2 : l 1537
Trying to write 0x78e3b80 at offset : 0x60 HWREG(SYSCTL_RCC) = ulRCC;
Trying to write 0x7802800 at offset : 0x70 HWREG(SYSCTL_RCC2) = ulRCC2;


QEMU: Terminated
</pre>
Le fait de dérouler le code de l'appel de la fonction nous a permis de cibler
les erreurs et de comprendre comment les traiter.
De cette facon nous avons pu émuler l'horloge.
Cette façon d'avancer dans le developpement est assez fastidieuse mais assure de
ne pas faire d'erreur et d'avoir bien compris ce qu'il se passe.
L'utilisation d'un outil de debuggage est recommandé.

==SSD0323==
Le fichier ssd0323 correspond à l'interface entre l'OLED et le bus SSI sur la carte.
Les les commandes et données du bus SSI sont passées en paramètre de la fonction
ssd0323_transfer.
A partir de cette fonction, on pilote l'OLED selon les spécification fournie dans
la documentation. (voir Treiber_IC-SSD0323_OLED_128x64_GELB et SSD1329_1.1)
De base, l'interface émulée etait la SSD0323 commme l'indique le fichier, mais
il a fallu ajouter des fonctions comprise dans le SSD1329 pour qu'il n'y ait plus
d'erreur apparante à l'éxécution.

Details de la fonction ssd0323_transfer :
Cette fonction récupère commandes et données. Pour faire la différence entre les
deux il faut regarder le champ mode de la structure.
Pour les données, un travail effectué pour conserver la position du curseur de l'OLED
Pour les commandes, une astuce est utilisée pour recuperer la commande dans un premier
temps puis les paramètres. En fait, tant que le nombre de paramètre n'est pas bon,
le paramètre courant est stocké.
(Voir le traitement fait à l'entrée du case l93 et la macro DATA définie )
Le detail des commandes est un peu commenté, pour plus d'info voir les fichier
sur le SSD0323 et SSD1329 à la section de la liste des commandes.

Details de la structure : Les champs de la structures sont utiles pour
la simulation des commandes.
Les noms des entiers utilisés sont assez explicite. De plus il est assez intuitif
d'avoir un SSIDev dans la structure étant donné que c'est l'interface.
De même pour la présence du DisplayState.


==PL061 ==
Le fichier pl061.c correpond aux registres GPIO. Il a la même structure que les
autres fichiers (fonction pour lire/ecrire/initialiser, structure d'info ...)
Le pl061 est connecté à l'APB (Advanced Peripheral Bus) sur la carte le Bus utilisé
lors d'un accès à un péripherique.
Les GPIO sont très souvent utilisés dans les programmes de test disponible
(OLED par exemple)


==Détails sur différentes structures==
===Details sur la création d'un device===
La fonction qdev_create est utilisée pour creer des peripheriques. Elle est située
dans le fichier qdev.c. Cette fonction n'est pas directement appellée dans stellaris.c.
On peut la trouver par exemple dans ssi_create_slave.
La fonction a besoin d'information sur le péripherique pour pouvoir le creer.
De telles informations sont déclarées dans des structures que l'on peut trouver dans
stellaris (par exemple). Ces structures ont un formatage particulier, il faut faire attention.
Il faut également spécifier un bus, sinon c'est celui du système qui est pris par défaut.

Exemple :
<pre>
static SSISlaveInfo stellaris_ssi_bus_info = {
.qdev.name = "evb6965-ssi",
.qdev.size = sizeof(stellaris_ssi_bus_state),
.init = stellaris_ssi_bus_init,
.transfer = stellaris_ssi_bus_transfer
};
</pre>

===Details sur l'ajout d'un device ===
Dans qdev.c on peut trouver la fonction suivante :
DeviceState *qdev_device_add(QemuOpts *opts)
Cette fonction recupère les options pour creer un driver.
Ensuite elle recupère les infos relatives à ce driver puis le bus correspondant
A partir du bus et des infos elle créée un device et met les propriétés.


===Détails sur la création d'un QemuOpts===
Dans qemu-options.c on trouve la fonction suivante :
QemuOpts *qemu_opts_create(QemuOptsList *list, const char *id, int fail_if_exists)
Elle se contente de verifier la forme de l'id et recuperer les options dans la liste
afin de les placer dans la structure à retourner.

Les QemuOptsList sont à initialiser à la main à priori le detail de cette structure
se trouve dans qemu-options.h



= Image de machine virtuelle =
L'image de machine virtuelle ci-dessous contient les outils adaptés pour le LM3S6965EVB comme présenté précédemment: la chaîne de compilation Sourcery G++ Lite, l'outil de pilotage de sonde matérielle OpenOCD, et QEMU.

* Image de système au format vdi pour VirtualBox: [http://mescal.imag.fr/membres/olivier.richard/documents/debian_air_32bit.vdi]



= FAQ =

==Quels sont les composants reconnus de la carte?==

:Extrait de la [http://qemu.weilnetz.de/qemu-doc.html#ARM-System-emulator Documentation Officielle] :

<pre>
The Luminary Micro Stellaris LM3S6965EVB emulation includes the following devices:


Cortex-M3 CPU core.
*Site officiel du [http://www.luminarymicro.com/products/lm3s6965_ethernet_evaluation_kit.html kit Stellaris Luminary Lm3s6965]
256k Flash and 64k SRAM.
Timers, UARTs, ADC, I^2C and SSI interfaces.
OSRAM Pictiva 128x64 OLED with SSD0323 controller connected via SSI.
</pre>

Latest revision as of 22:22, 6 April 2011

N'hésitez pas à enrichir cette page

Stellaris Luminary Lm3s6965

Ce kit est construit autour d'un microcontrolleur ARM Cortex-M3 Lm3s6965 de marque Luminary Micro appartenant au groupe Texas Instrument.

Les principales caratéristiques et intérêts de ce kit sont:

  • Processeur ARM 32bit Cortex-M3
  • Port Ethernet
  • Ecran OLED monochrome 128 x 64 pixels (16 niveaux)
  • Un bon support d'OpenOCD
  • Support de eLua (port du langage de script Lua)


Ressources

  • LM3S6965: Tips & Tricks / OpenOCD : [1]
  • Building toolchain and OpenOCD for Stellaris on Linux : [2]
  • Test qemu + arm + gdb + ld ... :[3]
  • ARM Projets divers : [4]

Exemples d'utilisation

Les exemples ci-dessus rassemblent un ensemble d'outils et de codes complétant ceux proposé par le constructeur dans une vision opensource. Une image virtuelle est aussi fournie, voir ci-dessous.

Debut avec la Carte Stellaris

Pour programmer la carte, il faut tout d'abord installer la chaîne de compilation.

Compilation du toolchain

Suivre Binaire Linux pour récupérer la chaîne de compilation Sourcery G++ Lite.
D'autres paquets disponibles sur le site du logiciel


Compilation des exemples

Une fois le toolchain installé, il est intéressant de regarder les fichiers de tests disponible sur le CD d'Installation. L'éxecutable SW-EK-LM3S6965.exe propose un grand nombre de test recompilable à l'aide des fichiers adjacents. Ces codes étant fournis par le constructeur, ce sont eux qui vont valider la bonne émulation de la carte.


Compilation d'exemples plus simples

Les fichiers test-cortex-m3.c, startup_gcc.c et lm3s.ld utilisés ci-aprés sont disponibles dans l'archive: Media:Test-cortex-m3.tar

Construction de l'exécutable

arm-none-eabi-gcc -c -mcpu=cortex-m3 -mthumb test-cortex-m3.c -o test-cortex-m3.o
arm-none-eabi-gcc -c -mcpu=cortex-m3 -mthumb startup_gcc.c -o startup_gcc.o
arm-none-eabi-ld -T lm3s.ld  startup_gcc.o test-cortex-m3.o -o test-cortex-m3.elf
arm-none-eabi-nm test-cortex-m3.elf


Juste pour voir le code déassemblé

arm-none-eabi-objdump -d test-cortex-m3.elf


Il faut une version binaire simple à charger et non la version trop riche

arm-none-eabi-objcopy -O binary test-cortex-m3.elf test-cortex-m3.bin

Le binaire peut ensuite être placé(flashé) sur la carte avec OpenOCD ou utilisé avec l'émulateur QEMU, voir ci-dessous.


Chargement du bin sur la carte

Utilisation avec OpenOCD sous linux

Récupérer le script setup_lm3s6965.sh sur [5]. Ce script va récupérer et compiler openocd. Une copie est disponible Media:Setup_lm3s6965.txt

sh setup_lm3s6965.txt

Construire et installer le bon pilote FTDI

 wget http://www.intra2net.com/en/developer/libftdi/download/libftdi-0.18.tar.gz
 #install open FTDI drivers
 tar -xzf libftdi-0.18.tar.gz
 cd libftdi-0.18/
 sudo apt-get install libusb-dev
 ./configure
 make
 sudo make install
 sudo ldconfig

On lance openocd en root

sudo openocd -f /usr/local/share/openocd/scripts/board/ek-lm3s6965.cfg

Et on peut flash le microcontrolleur

 #flash mcu with some code at address 0x00000 and execute
 telnet localhost 4444
 halt
 flash write_image erase /tmp/main.bin 0
 reset

Exemple avec le déboggeur gdb


Debut avec QEMU

Compilation et première utilisation

Récupération et compilation du qemu version qemu-0.13.0

wget http://wiki.qemu.org/download/qemu-0.13.0.tar.gz
tar zxvf qemu-0.13.0.tar.gz
cd qemu-0.13.0
./configure --target-list=arm-softmmu # On configure pour ne pas tout compiler
make

Note : La version qemu-0.14.0 a été réalisée le 18/02/11

Lancement de l'émulation avec qemu (faire crtl a + x pour sortir ou crtl a + c pour accéder au moniteur)

./qemu-0.13.0/arm-softmmu/qemu-system-arm -M lm3s6965evb -nographic -kernel test-cortex-m3.bin
Hello world!
QEMU 0.13.0 monitor - type 'help' for more information
(qemu) quit


Moniteur (console de commande et d'interrogation de Qemu)

Qemu dispose d'un moniteur assez puissant. Utilisez l'option -S pour lancer le moniteur dès le démarrage l'émulation sera alors suspendu, puis faire crtl+a c pour accèder à la console d moniteur

./qemu-0.13.0/arm-softmmu/qemu-system-arm -S -M lm3s6965evb -nographic -kernel test-cortex-m3.bin
 crtl+a c
(qemu) info roms 
addr=00000000 size=0x0001e0 mem=rom name="test-cortex-m3.bin" 
(qemu) info registers 
R00=000001d0 R01=20000000 R02=0000000a R03=00000000
R04=00000000 R05=00000000 R06=00000000 R07=2000fff0
R08=00000000 R09=00000000 R10=00000000 R11=00000000
R12=00000000 R13=2000fff0 R14=000001c9 R15=00000160
PSR=60000173 -ZC- T svc32

Malheureusement pour une émulation des cpus cortex-M3, l'ensemble des fonctions du moniteur ne sont pas toutes supportées. Par exemple le déassembleur intégré ne décode pas correctement les instructions. Pour aller plus loin, il faut utiliser le déboggeur cf suite.

Qemu et GDB

On peut attaché GDB à Qemu

./qemu/qemu-0.13.0/arm-softmmu/qemu-system-arm -M lm3s6965evb -nographic -monitor null -serial null -semihosting  -kernel  /tmp/hello.bin  -S  -gdb tcp::51234
arm-none-eabi-gdb /tmp/hello.axf 
(gdb) target remote localhost:51234
... 
(gdb) load
(gdb) break main
(gdb) continue
  Continuing.
  Breakpoint 1, 0x000000f4 in main ()
(gdb) stepi
  0x00000640 in SysCtlClockSet ()
(gdb) disassemble 0x640
  Dump of assembler code for function SysCtlClockSet:
  0x00000640 <SysCtlClockSet+0>:	ldr	r3, [pc, #308]	; (0x778 <SysCtlClockSet+312>)
  0x00000642 <SysCtlClockSet+2>:	push	{r4, r5, r6, lr}
  0x00000644 <SysCtlClockSet+4>:	ldr	r2, [r3, #0]
  ....

On peut attaché GDB à Qemu

http://cgi.cs.indiana.edu/~geobrown/stm32/Main/Simulation
http://garden.seeedstudio.com/index.php?title=DSO_Nano/Qemu_gdb&redirect=no


Modifications réalisées sur QEMU

Suivi et accès des GPIO en sortie

Le principe va être d'utiliser le code élémentaire de clignotement de LED blinky.bin disponible dans le répertoire StellarisWare puis de modifier le fichier stellaris.c dans repertoire hw de qemu pour repérer et intercepter les changement d'état


Comprendre l'émulation du stellaris proposé par QEMU suppose de se plonger dans le code. On peut notamment explorer les fichiers suivant, liste non exhaustive:

hw/irq.c  hw/qdev.c  hw/stellaris.c       hw/stellaris_input.c  hw/sysbus.h
hw/irq.h  hw/qdev.h  hw/stellaris_enet.c  hw/sysbus.c           qemu-common.h


Il est important d'observer la struct qemu_irq. Dans le stellaris.c nous notons la déclaration suivante

static void stellaris_init(const char *kernel_filename, const char *cpu_model,
                          stellaris_board_info *board)
{
   static const int uart_irq[] = {5, 6, 33, 34};
   static const int timer_irq[] = {19, 21, 23, 35};
   static const uint32_t gpio_addr[7] =
     { 0x40004000, 0x40005000, 0x40006000, 0x40007000,
       0x40024000, 0x40025000, 0x40026000};
   static const int gpio_irq[7] = {0, 1, 2, 3, 4, 30, 31};
   qemu_irq *pic;
   DeviceState *gpio_dev[7];
   qemu_irq gpio_in[7][8];
   qemu_irq gpio_out[7][8];

La déclaration qemu_irq gpio_out[7][8]; va permettre l'émulation des 8 fils de sortie des 7 port d'E/S (A,B,C,D,E,F,G).

Si on suit 'qemu_irq à travers les fichiers, nous avons:

Dans qemu-common.h qemu_irq est un pointer sur IRQState

typedef struct IRQState *qemu_irq;

IRQState dans hw/irq.c

struct IRQState {
   qemu_irq_handler handler;
   void *opaque;
   int n;
};

Dans hw/irq.h:

typedef void (*qemu_irq_handler)(void *opaque, int n, int level);

qemu_irq_handler est un pointeur sur une fonction qui sera appelée lorsque le fils changera de valeur, voir la fonction qemu_set_irq dans irq.c:

void qemu_set_irq(qemu_irq irq, int level)
{
   if (!irq)
       return;
   irq->handler(irq->opaque, irq->n, level);
}

On va maintenant maintenant de modifier le fichier stellaris.c pour suivre l'état du bit 0 du port F en sortie lequel est cablé un LED sur la carte physique (utilisé par le code blinky.bin).

 static void print_yop(void *opaque, int line, int level)
 {
  /* opaque is null, can by use to access to a global state ??? */
  printf("poy line %d level %d\n",line,level);
 }
qemu_irq yop; /*test*/
yop =  qemu_allocate_irqs(print_yop, NULL, 1)[0]; /* on alloue de ma mémoire  et on positionne le handler, ici print_yop*/
gpio_out[GPIO_F][0] = yop; /* /!\ à faire après l'intialisation de tous les gpio_out, si il y a écrassement */

Archive contenant le fichier modifié stellaris.c et le code de clignotement de LED blinky.bin Media:stellaris_mod_blinky.tar

./qemu-0.13.0/arm-softmmu/qemu-system-arm -M lm3s6965evb -nographic -kernel blinky.bin
poy line 0 level 1 
poy line 0 level 0
poy line 0 level 1
poy line 0 level 0
poy line 0 level 1
poy line 0 level 0

Note Ctrl A puis x quitter QEMU, voir les commandes du moniteur pour plus de détail.


Affichage de Caractères sur l'OLED

Ajout d'un registre d'horloge

Les programmes de test de l'OLED fournis ne fonctionnent pas en tant que tels. Qemu affiche une erreur dès le début de l'exécution. Après des recherches dans le code des fonctions utilisées dans les exemples. Il vient qu'il est nécessaire de modifier les fonctions ssys_read et ssys_write de stellaris.c en ajoutant un cas supplémentaire.

    case 0x070: /* RCC2 */
    return s->rcc2;

et

      case 0x070 : /* RCC2 */						
			//p95 datasheet	Register 10: Run-Mode Clock Configuration 2 
		
		if(value >> 31 != 0 ){	// if the USERCC2 bit is to 1 we
			s->rcc=value;			// override RCC;
		}
		
		if ((s->rcc2 & (1 << 13)) != 0 && (value & (1 << 13)) == 0) { 
                    /* PLL enable.  */
                    s->int_status |= (1 << 6);
                }
		
		s->rcc2 = value;
		break;

Le champs rcc2 de la structure s a été ajouté également. Ce champ correspond au registre Run-Mode Clock Configuration 2 (RCC2) décrit dans le datasheet.

Ajout d'un registre déprécié

Rédaction en Cours


Documentation

Une documentation sommaire a été réalisée afin que les personnes continuant le projet puisse comprendre ce qui a déjà été fait. Elle contient également quelques explications de la structure de Qemu et les fonctions. Le code n'étant pas très commenté, il est difficile à appréhender.


Présentation Générale

Ce texte présente brievement comment marche globalement l'émulation de la carte Stellaris et quelques points importants pour comprendre le fonctionnement.

De la documentation spécifique à certains fichier est disponible. Elle est plutot sommaire la plupart du temps mais permet d'appréhender mieux le système.

La majeur partie de l'émulation de la carte Stellaris est réalisée dans le fichier stellaris.c du dossier hw de Qemu. On peut trouver dans ce fichier la déclaration de plusieurs structures correpondant au convertisseur analogique numérique (adc), ssi, timer (gptm) et i2c. Ensuite, on trouve les fonctions de lecture et d'ecriture dans les registres systemes. Les 29 Registres systemes sont décrit dans le DataSheet de Stellaris. (Attention, certains commentaires de code redirige vers un Datasheet plus ancien que celui qu'on peut trouver sur le site du constructeur)

Stellaris utilise également des éléments extérieurs pour fonctionner. L'OLED fait parti de ces éléments, étant donné qu'il peut être utilisé dans d'autres carte.


Pour comprendre comment est émulé la carte, il est important de partir des tests de base proposés sur le CD de Stellaris. Les bin donnés en paramètres de qemu "simulent" déjà une partie du code donné. Par exemple : le fichier hello.c appelle la fonction RIT128x96x4StringDraw avec le paramètre "Hello World!". La compilation du programme va "déjà" modifier le paramètre entré pour le mettre sous la forme de donnée en hexadécimal transmises à l'OLED. C'est logique, étant donné que les bin seront éxécutés aussi sur la carte.


Cependant la compréhension de ce code est indispensable pour pouvoir ajouter des fonctionnalités à qemu. Il faut savoir quelles sont les infos contenues dans le bin afin de pouvoir les traiter et simuler le comportement réél. Exemple pour une fonction largement répandue dans les fichiers de test :

	Decomposition de l'exécution de l'appel à SysCtlClockSet (fichier sysctl.c)

	Sortie console : 

	//Debut Qemu 
	Trying to read at offset : 0x0 //Printf ajoutés dans ssys_read 
	Trying to read at offset : 0x0

	Début fonction : l 1367
	Ne rentre pas dans le if du début :
	CLASS_IS_SANDSTORM && (ulConfig & SYSCTL_RCC2_USERCC2)

	Lecture de RCC et RCC2 : l 1389
	Trying to read at offset : 0x60		ulRCC = HWREG(SYSCTL_RCC);		 
	Trying to read at offset : 0x70		ulRCC2 = HWREG(SYSCTL_RCC2);		

	Calculs...

	Ecriture de RCC et RCC2 : l 1402
	Trying to write 0x78e3ac0 at offset : 0x60  	HWREG(SYSCTL_RCC) = ulRCC;
	Trying to write 0x800 at offset : 0x70 			HWREG(SYSCTL_RCC2) = ulRCC2;


	N'entre pas dans le if : 
	(((ulRCC & SYSCTL_RCC_IOSCDIS) && !(ulConfig & SYSCTL_RCC_IOSCDIS)) ||
    ((ulRCC & SYSCTL_RCC_MOSCDIS) && !(ulConfig & SYSCTL_RCC_MOSCDIS)))
	L'oscillateur n'a pas besoin d'être activé
	Calculs...


	Ecriture MISC : l 1468
	// Clear the PLL lock interrupt
	HWREG(SYSCTL_MISC) = SYSCTL_INT_PLL_LOCK;
	Trying to write 0x40 at offset : 0x58


	Passe dans le else : !ulRCC2 & SYSCTL_RCC2_USERCC2
	
	Ecriture de RCC et RCC2 : l 1480
	Trying to write 0x78e3b80 at offset : 0x60	HWREG(SYSCTL_RCC) = ulRCC;
	Trying to write 0x2800 at offset : 0x70		HWREG(SYSCTL_RCC2) = ulRCC2;


	Ecriture de RCC et RCC2 : l 1537
	Trying to write 0x78e3b80 at offset : 0x60    HWREG(SYSCTL_RCC) = ulRCC;
	Trying to write 0x7802800 at offset : 0x70 	HWREG(SYSCTL_RCC2) = ulRCC2;


	QEMU: Terminated

Le fait de dérouler le code de l'appel de la fonction nous a permis de cibler les erreurs et de comprendre comment les traiter. De cette facon nous avons pu émuler l'horloge. Cette façon d'avancer dans le developpement est assez fastidieuse mais assure de ne pas faire d'erreur et d'avoir bien compris ce qu'il se passe. L'utilisation d'un outil de debuggage est recommandé.

SSD0323

Le fichier ssd0323 correspond à l'interface entre l'OLED et le bus SSI sur la carte. Les les commandes et données du bus SSI sont passées en paramètre de la fonction ssd0323_transfer. A partir de cette fonction, on pilote l'OLED selon les spécification fournie dans la documentation. (voir Treiber_IC-SSD0323_OLED_128x64_GELB et SSD1329_1.1) De base, l'interface émulée etait la SSD0323 commme l'indique le fichier, mais il a fallu ajouter des fonctions comprise dans le SSD1329 pour qu'il n'y ait plus d'erreur apparante à l'éxécution.

Details de la fonction ssd0323_transfer : Cette fonction récupère commandes et données. Pour faire la différence entre les deux il faut regarder le champ mode de la structure. Pour les données, un travail effectué pour conserver la position du curseur de l'OLED Pour les commandes, une astuce est utilisée pour recuperer la commande dans un premier temps puis les paramètres. En fait, tant que le nombre de paramètre n'est pas bon, le paramètre courant est stocké. (Voir le traitement fait à l'entrée du case l93 et la macro DATA définie ) Le detail des commandes est un peu commenté, pour plus d'info voir les fichier sur le SSD0323 et SSD1329 à la section de la liste des commandes.

Details de la structure : Les champs de la structures sont utiles pour la simulation des commandes. Les noms des entiers utilisés sont assez explicite. De plus il est assez intuitif d'avoir un SSIDev dans la structure étant donné que c'est l'interface. De même pour la présence du DisplayState.


PL061

Le fichier pl061.c correpond aux registres GPIO. Il a la même structure que les autres fichiers (fonction pour lire/ecrire/initialiser, structure d'info ...) Le pl061 est connecté à l'APB (Advanced Peripheral Bus) sur la carte le Bus utilisé lors d'un accès à un péripherique. Les GPIO sont très souvent utilisés dans les programmes de test disponible (OLED par exemple)


Détails sur différentes structures

Details sur la création d'un device

La fonction qdev_create est utilisée pour creer des peripheriques. Elle est située dans le fichier qdev.c. Cette fonction n'est pas directement appellée dans stellaris.c. On peut la trouver par exemple dans ssi_create_slave. La fonction a besoin d'information sur le péripherique pour pouvoir le creer. De telles informations sont déclarées dans des structures que l'on peut trouver dans stellaris (par exemple). Ces structures ont un formatage particulier, il faut faire attention. Il faut également spécifier un bus, sinon c'est celui du système qui est pris par défaut.

Exemple :

static SSISlaveInfo stellaris_ssi_bus_info = {
    .qdev.name = "evb6965-ssi",
    .qdev.size = sizeof(stellaris_ssi_bus_state),
    .init = stellaris_ssi_bus_init,
    .transfer = stellaris_ssi_bus_transfer
 };

Details sur l'ajout d'un device

Dans qdev.c on peut trouver la fonction suivante : DeviceState *qdev_device_add(QemuOpts *opts) Cette fonction recupère les options pour creer un driver. Ensuite elle recupère les infos relatives à ce driver puis le bus correspondant A partir du bus et des infos elle créée un device et met les propriétés.


Détails sur la création d'un QemuOpts

Dans qemu-options.c on trouve la fonction suivante : QemuOpts *qemu_opts_create(QemuOptsList *list, const char *id, int fail_if_exists) Elle se contente de verifier la forme de l'id et recuperer les options dans la liste afin de les placer dans la structure à retourner.

Les QemuOptsList sont à initialiser à la main à priori le detail de cette structure se trouve dans qemu-options.h


Image de machine virtuelle

L'image de machine virtuelle ci-dessous contient les outils adaptés pour le LM3S6965EVB comme présenté précédemment: la chaîne de compilation Sourcery G++ Lite, l'outil de pilotage de sonde matérielle OpenOCD, et QEMU.

  • Image de système au format vdi pour VirtualBox: [6]


FAQ

Quels sont les composants reconnus de la carte?

Extrait de la Documentation Officielle :
The Luminary Micro Stellaris LM3S6965EVB emulation includes the following devices:

Cortex-M3 CPU core.
256k Flash and 64k SRAM.
Timers, UARTs, ADC, I^2C and SSI interfaces.
OSRAM Pictiva 128x64 OLED with SSD0323 controller connected via SSI.