Documente Academic
Documente Profesional
Documente Cultură
PC
(openocd,
stflash)
STLINK
STM32VL discovery
PC8 PC9 ADC1 USART1
added 150116
1. http://libopencm3.org/wiki/Main_Page mais le plus simple est de slectionner cette bibliothque lors de la compilation de sa toolchain par
https://github.com/vedderb/summon-arm-toolchain/
6
8
10
12
14
16
18
20
22
24
26
28
30
32
34
36
38
40
42
LDSCRIPT= ld / stm32_flash . ld
44 #LDSCRIPT= . / stm32vldiscovery . ld
46 usart_stm32 . bin : main_stm32 . c . . /common/ usart_stm32 . c system_stm32f10x . c
armnoneeabigcc DSTM32F10X_LD_VL I . / c fnocommon O0 g3 I /home/ j m f r i e d t / s a t /armnoneeabi / include / stm32f1 / I /
home/ j m f r i e d t / s a t /armnoneeabi / include / Wall Wextra mcpu=cortexm3 mthumb I /home/ j m f r i e d t / s a t /armnoneeabi /
include / include fnocommon mthumb msoftf l o a t
c o usart_stm32 . o . . /common/ usart_stm32 . c
48
armnoneeabigcc DSTM32F10X_LD_VL I . / c fnocommon O0 g3 I /home/ j m f r i e d t / s a t /armnoneeabi / include / stm32f1 / I /
home/ j m f r i e d t / s a t /armnoneeabi / include / Wall Wextra mcpu=cortexm3 mthumb I /home/ j m f r i e d t / s a t /armnoneeabi /
include / include fnocommon mthumb msoftf l o a t
c o main_stm32 . o main_stm32 . c
armnoneeabigcc fnocommon O0 g3 Wall Wextra mcpu=cortexm3 mthumb mthumb msoftf l o a t Wl,gcsections T$ (
LDSCRIPT) n o s t a r t f i l e s L~/ s a t /armnoneeabi / l i b /thumb/ cortexm3 o usart_stm32 . e l f main_stm32 . o usart_stm32 . o
lstm32 lopencm3_stm32f1
50
armnoneeabiobjcopy O binary usart_stm32 . e l f usart_stm32 . bin
52 clean :
rm * . o * . bin * . d * . e l f
Cependant, cette approche a le mauvais got de faire planter le bootloader aprs cette transaction et de ncessiter de dbrancher/rebrancher le cble USB afin de relancer le Discovery Board.
Une alternative consiste passer par gdb, qui en plus nous donne accs aux outils de dverminage associs (affichage de la
pile, des valeurs des variables ...). Dans un premier terminal nous lanons
openocd -s /usr/local/share/openocd/scripts/ -f board/stm32vldiscovery.cfg qui lance le serveur. Dans un second terminal, le client gdb pour la cible approprie est lanc avec pour argument le programme (au format ELF, idalement
avec les symboles de dverminage compils par -g) et le programme est charg par
arm-none-eabi-gdb output/main.elf
Une fois gdb lanc, nous le connectons au client et chargeons le programme par
target remote localhost:3333
load
continue
En particulier, lintrt de gdb est de permettre dinterrompre lexcution du programme pour observer ltat de la pile (bt),
afficher une variable (print c) ou placer des points darrt (break fonction, par exemple break uart_putc).
En cas derreur de liaison, vrifier que la carte de dveloppement nest pas considre comme un priphrique de stockage
de masse : dmesg doit indiquer usb-storage : device ignored. Dans le cas contraire, ajouter une condition au chargement du module usb-storage en crant le fichier /etc/modprobe.d/usb-storage.conf contenant options usb-storage
quirks=483:3744:i
1. Faire clignoter alternativement les deux LEDs (PC8 et PC9). Varier la vitesse de clignotement.
2. Afficher la chane de caractres Hello World au moyen dune fonction prenant en entre un tableau de caractres.
Nous profitons de cet exemple pour sensibiliser sur limpact dutiliser inconsidrment une bibliothque. Avec lutilisation
de newlib pour une fonctionnalit telle que printf, la taille du code rsultant est
Nous obtenons exactement le mme rsultat en crivant la main les fonctions de gestion de laffichage de chanes de
caractres, et en vitant newlib nous rduisons la taille
Lutilisation de FreeRTOS naffranchit donc pas de lire une datasheet et sapproprier les mthodes daccs aux priphriques. Les exemples fournis dans https://github.com/libopencm3/libopencm3-examples permettent daborder sereinement cette architecture.
1234 :
4 Du C FreeRTOS
FreeRTOS (www.freertos.org) amne un niveau dabstraction additionnel par rapport la programmation en C par lajout
dun scheduler et de la notion de tches avec des priorits. Il sagit dun environnement excutif, donc une mthode de travail
qui donne limpression du point de vue du dveloppeur davoir accs des mthodes fournies par un systme dexploitation,
mais avec gnration dun binaire monolithique et donc dterministe qui ne peut pas charger dynamiquement des excutables
ou des bibliothques. FreeRTOS est un OS temps rel, signifiant quil borne les latences daccs un processus.
La multitude des processeurs dclins autour de larchitecture STM32 impose de prendre soin de bien dfinir les capacits du
processeur et les priphriques disponibles. En particulier dans le Makefile, dfinir la nature du processeur (-DSTM32F10X_LD_VL
pour les processeurs les plus petits, -DSTM32F10X_MD pour les composants de densit moyenne MD) est un point fondamental
sans lequel le programme ne peut sexcuter faute dune initialisation approprie.
En cas dchec de lexcution sur la carte STM32-Discovery, vrfier que la ligne -DSTM32F10X_LD_VL est active.
1basic/src/main.c
qh = xQueueCreate ( 1 , s i z e o f ( i n t ) ) ;
83 //
85
87
i f ( ! ( pdPASS == xTaskCreate ( task_tx , ( signed char * ) " t1 " , 100 , 0 , 2 , 0) ) ) goto h e l l ;
i f ( ! ( pdPASS == xTaskCreate ( task_rx , ( signed char * ) " t2 " , 100 , 0 , 2 , 0) ) ) goto h e l l ;
vTaskStartScheduler ( ) ;
91 h e l l : while ( 1 ) ;
return 0 ;
93 }
// attention a l a t a i l l e de l a p i l e
89
2message_passing/src/main.c
1. ajouter les tches commentes et observer la consquence en terme de gestion du temps par lordonnanceur.
#include
5 #include
#include
7 #include
9 i n t global =0;
//xSemaphoreHandle xMutex ;
11
i n t main( void ) ;
13 void Led_Init ( void ) ;
void U sart1_Init ( void ) ;
15 void uart_putc ( char c ) ;
void uart_puts ( char * c ) ;
17 void vLedsFloat ( void * dummy) ;
void vLedsFlash ( void * dummy) ;
19 void vPrintUart ( void * dummy) ;
21 void t a s k _ r x ( void * p)
{
char a f f [ 1 0 ] ;
23
char * t =( char * ) p ;
i n t myInt = 0 ;
25
volatile int local ;
f o r ( myInt =0; myInt <8; myInt++)
27
{
//
xSemaphoreTake ( xMutex , portMAX_DELAY ) ;
29
l o c a l =global ;
l o c a l ++;
31
uart_puts ( t ) ;
// c e t t e operation nous f a i t perdre beaucoup de temps . . . i l y a toutes l e s
33 // chances pour que l a seconde tache se lance pendant cet i n t e r v a l l e de temps . . . mais l a seconde tache
// va cherche global qui n a pas encore ete incremente et l e r e s u l t a t sera errone puisque l e s 16 taches
35 // auront f a i t une somme de 8
global= l o c a l ;
37
//
xSemaphoreGive ( xMutex ) ;
39
vTaskDelay ( ( rand ( ) & 0x1 ) ) ; // essayer de deplacer l e delay sous c e t t e } pour ne pas a l t e r n e r
}
41
a f f [ 0 ] = ; a f f [ 1 ] = global+ 0 ; a f f [ 2 ] = ; a f f [ 3 ] = 0 ; uart_puts ( a f f ) ;
while ( 1 ) vTaskDelay ( ( rand ( ) & 0x5 ) ) ; // on n a jamais l e d r o i t de f i n i r toutes l e s taches
43 }
45 i n t main ( )
{
47
Led_Init ( ) ;
Usart1_Init ( ) ;
49
srand ( 567 ) ;
//
xMutex = xSemaphoreCreateMutex ( ) ;
51
xTaskCreate ( task_rx , ( signed char * ) " t1 " , (100) , " 1111111111111111111111111111111111111111111\ r \n\0 " , 1 , 0) ;
xTaskCreate ( task_rx , ( signed char * ) " t2 " , (100) , " 2222222222222222222222222222222222222222222\ r \n\0 " , 1 , 0) ;
53
vTaskStartScheduler ( ) ;
55 h e l l :
while ( 1 ) ;
57
return 0 ;
}
texte1/main_mutex.c
Lexemple ci-dessus considre une variable globale globale qui est manipule par deux tches. Chacune de ces tches
effectue un calcul long, illustr ici par un transfert sur le port srie (une tche trs longue lchelle du temps de calcul : rappeler
la dure dun transfert de 45 caractres au dbit de 115200 bauds selon un encodage 8N1 sur bus RS232).
Afin de pallier aux dficiences observes, nous utiliserons un mutex.
1. Dcommenter les lignes contenant la dclaration des mutex, et constater la diffrence de comportement.
Attention : nous devons informer FreeRTOS de notre intention dutiliser les mutex et donc de charger les fonctionnalits associes. Nous devons pour cela ajouter la configuration #define configUSE_MUTEXES 1 dans src/include/FreeRTOSConfig.h.
"FreeRTOS . h"
" task . h"
"queue . h"
"semphr . h"
" croutine . h"
10 i n t globale =0;
xSemaphoreHandle event_signal ;
12
i n t main( void ) ;
14 void Usart1 _Ini t ( void ) ;
void uart_putc ( char c ) ;
16 void uart_puts ( char * c ) ;
void vPrintUart ( void * dummy) ;
18
void task1 ( void * p)
20 {
while ( 1 ) {
22 //
i f ( xSemaphoreTake ( event_signal ,500/portTICK_RATE_MS ) ==pdFALSE)
//
uart_puts ( " not a v a i l a b l e \ r \n\0") ;
24 //
else
//
uart_puts ( "sem take \ r \n\0") ;
26
while ( globale ==0) ; // vTaskDelay ( 1/portTICK_RATE_MS ) ;
28
globale =0;
uart_puts ( "sem take \ r \n\0 " ) ;
30 // i c i on demontre que l e semaphore e s t bien f a i t car i l rend l a main en cas de blocage ,
// contrairement au cas de l a v a r i a b l e globale qui , en l absence de Delay , va bloquer sur
32 // l a tache p r i o r i t a i r e qui ne rend pas l a main
}
34 }
36 void task2 ( void * p)
{
38
while ( 1 ) {
//
xSemaphoreGive ( event_signal ) ; // debloque tache 1
40
globale =1;
uart_puts ( "sem give \ r \n\0 " ) ;
42
vTaskDelay ( 700/portTICK_RATE_MS ) ; // remplacer 400 par 700 !
}
44 }
46 i n t main ( )
{
48 Usart1_Init ( ) ;
uart_puts ( " depart \ r \n\0 " ) ;
50 //
vSemaphoreCreateBinary ( event_signal ) ;
// Create the semaphore
//
xSemaphoreTake ( event_signal , 0) ;
// Take semaphore a f t e r creating i t .
52 xTaskCreate ( task1 , ( signed char * ) " t1 " , (100) , 0 , 2 , 0) ;
xTaskCreate ( task2 , ( signed char * ) " t2 " , (100) , 0 , 1 , 0) ;
54 vTaskStartScheduler ( ) ;
56 h e l l :
while ( 1 ) ;
58
return 0 ;
}
texte1/semaphore.c
Cet exemple donne lieu de nombreuses combinaisons possibles si on se contente dessayer dmuler manuellement un
smaphore par une variable globale :
9
1. Si
while (globale==0) vTaskDelay( 1/portTICK_RATE_MS ); qui parfois donne la main task2 (qui est de faible
priorit)
3. si les priorits sont inverses par
5 Mise en pratique
Lexemple ci-dessous est une simple lecture priodique de temprature :
1 #include "stm32/ gpio . h"
#include "stm32/ usart . h"
3 #include <stm32/ rcc . h>
#include <cmsis /stm32 . h>
5 #include <stm32/ f l a s h . h>
#include <stm32/misc . h>
7 #include <stm32/adc . h>
#include <cmsis /stm32 . h>
9 #include < s t d l i b . h>
#include < s t r i n g . h>
11
uint16_t readADC( void ) ;
13 void initADC ( void ) ;
15 ADC_InitTypeDef ADC_InitStructure ;
17 unsigned short readADC1 ( unsigned char channel )
// jmf convert ADC1
{ ADC_RegularChannelConfig (ADC1, channel , 1 , ADC_SampleTime_239Cycles5 ) ;
19 ADC_SoftwareStartConvCmd (ADC1,ENABLE) ;
while ( ADC_GetFlagStatus (ADC1,ADC_FLAG_EOC) ==RESET) ; // EOC i s s e t @ end of cv
21 return ( ADC_GetConversionValue (ADC1) ) ;
}
23
void writeHEXc ( unsigned char ptr )
25 { unsigned char b ;
b = ( ( ptr&0xf0 ) >>4) ;
27 i f ( b<10) uart_putc (b+48) ; e l s e uart_putc (b+55) ;
b = ( ( ptr&0x0f ) ) ;
29 i f ( b<10) uart_putc (b+48) ; e l s e uart_putc (b+55) ;
}
31
void writeHEXi ( uint16_t v a l )
33 { writeHEXc ( val >>8) ;
writeHEXc ( v a l&0 x f f ) ;
35 }
10
37 i n t main( void )
{ i n t i =0;
39 unsigned short tempe ;
GPIO_InitTypeDef GPIO_InitStructure ;
41
Led_Init ( ) ;
43
Usart1_Init ( ) ;
RCC_APB2PeriphClockCmd ( RCC_APB2Periph_AFIO | RCC_APB2Periph_ADC1 ,ENABLE) ;
45
/ * Configure USART1 RX (PA. 1 0 ) as input f l o a t i n g * /
47
GPIO_InitStructure . GPIO_Pin = GPIO_Pin_10 ;
GPIO_InitStructure . GPIO_Mode = GPIO_Mode_IN_FLOATING ;
49
GPIO_Init (GPIOA, &GPIO_InitStructure ) ;
51
// Configure ADC1
ADC_DeInit (ADC1) ;
53
ADC_InitStructure .ADC_Mode=ADC_Mode_Independent ;
ADC_InitStructure . ADC_ScanConvMode=DISABLE ;
ADC_InitStructure . ADC_ContinuousConvMode=DISABLE ;
ADC_InitStructure . ADC_ExternalTrigConv=ADC_ExternalTrigConv_None ;
ADC_InitStructure . ADC_DataAlign=ADC_DataAlign_Right ;
ADC_InitStructure . ADC_NbrOfChannel=1;
55
57
59
61
63
ADC_TempSensorVrefintCmd (ENABLE) ;
ADC_ResetCalibration (ADC1) ;
while ( ADC_GetResetCalibrationStatus (ADC1) ) ;
ADC_StartCalibration (ADC1) ;
while ( ADC_GetCalibrationStatus (ADC1) ) ;
65
67
69
while ( 1 )
{
tempe=readADC1 ( ADC_Channel_16 ) ;
writeHEXi ( tempe ) ; uart_putc ( ) ;
f o r ( i = 0 ; i < 80000; i ++) __asm__ ( "NOP" ) ;
}
71
73
75
}
temperature/main.c
avec initialisation des ADCs, des horloges associes ainsi que des broches.
La carte son se branche sur lADC canal 1 : remplacer la mesure de temprature par une mesure de tension.
Remplacer la lecture lente de temprature par une lecture de tension la plus rapide possible.
11
4000
tension (bits)
3500
3000
2500
2000
1500
1000
0
50
100
echantillon (sans unite)
150
200
Pour afficher une squence de donnes stockes en format hexadcimal dans un fichier ASCII, on utilisera sous GNU/Octave :
f=fopen("fichier");d=fscanf(f,"%x",inf); plot(d);
12
22
24
26
28
30
}
while ( 1 ) { vTaskDelay (100 / portTICK_RATE_MS ) ; } ; // on n a jamais l e d r o i t de f i n i r toutes l e s taches
32
}
34
i n t main ( )
36 {
//www. f r e e r t o s . org /FreeRTOS_Support_Forum_Archive/ February_2007 / freertos_Problems_with_passing_parameters_to_task_1666309 .
html
38
static int p[5]={0 ,1 ,2 ,3 ,4};
s t a t i c char * taskNames [ 5 ] = { "P0" , "P1" , "P2" , "P3" , "P4" } ;
40
int i ;
42
Led_Init ( ) ;
Usart1_Init ( ) ;
44
f o r ( i =0; i <NB_PHILO ; i ++) xMutex [ i ] = xSemaphoreCreateMutex ( ) ;
f o r ( i =0; i <NB_PHILO ; i ++)
46
{ xTaskCreate ( func , ( const signed char const * ) taskNames [ i ] , STACK_BYTES(256) , ( void * )&p [ i ] , 1 , 0 ) ; }
vTaskStartScheduler ( ) ;
48
while ( 1 ) ;
return 0 ;
50 }
philosophes.c
Ce programme renvoie la sortie juste eabcdEBnot available14DA03C2 puisque les 5 philosophes pensent, 1 et 4 mangent
puis reposent leurs baguettes alors que 3 se fait rejeter sa demande de nourriture, puis 3 et 0 mangent pour finalement laisser 2
salimenter
Le problme de deadlock apparat si une lattence existe entre la saisie de deux baguettes. Dans ce cas, chaque philosophe
peut avoir pris la baguette sa gauche et interdire son voisin dengager le repas : les ressources sont rserves et la condition de
dblocage ne peut tre rsolue. Cet exemple est illustr en dcommentant la constante deadlock dans lexemple de phthread :
la fonction usleep() autorise lordonnanceur passer la main une autre tche alors que seule une baguette a t prise, se
traduisant par un cas de blocage. Le solution consiste ce quau bout dun certain temps, le philosophe repose la baguette quil
a saisie et se remette penser, pour r-essayer de finir son repas plus tard. Cest le sens de la squence
if (xSemaphoreTake(xMutex[numero],500/portTICK_RATE_MS)==pdFALSE)
{uart_puts("not available\r\n\0");
xSemaphoreGive( xMutex[numero] );
qui ntait pas obligatoire si on suppose que les deux requtes de mutex se font simultanment et que lordonnanceur de peut
interrompre la tche entre les deux requtes.
Rfrences
[1] RM0008 Reference manual, STM32F101xx, STM32F102xx, STM32F103xx, STM32F105xx and STM32F107xx advanced ARMbased 32-bit MCUs, (May 2011), Doc ID 13902 Rev 13
[2] R. Barry, Using the FreeRTOS real time kernel A practical guide, (2009)
[3] J.J. Labrosse, MicroC OS II : The Real Time Kernel 2nd Ed., CRC Press (2002)
13
32
usart_enable (USART1) ;
34 }
36 void gpio_setup ( void )
{ gpio_set_mode (GPIOC,GPIO_MODE_OUTPUT_2_MHZ,GPIO_CNF_OUTPUT_PUSHPULL, GPIO9) ; }
38
// define newlib stub
40 # i f d e f avec_newlib
i n t _write ( i n t f i l e , char * ptr , i n t len )
42 { i n t i ;
i f ( f i l e == STDOUT_FILENO | | f i l e == STDERR_FILENO) {
44
f o r ( i = 0 ; i < len ; i ++) {
i f ( ptr [ i ] == \n ) { usart_send_blocking (USART1, \ r ) ; }
46
usart_send_blocking (USART1, ptr [ i ] ) ;
}
48
return i ;
}
50
errno = EIO ;
return 1;
52 }
# endif
14
19
21
23
25
gpio_i . GPIO_Pin
gpio_i . GPIO_Speed
gpio_i . GPIO_Mode
GPIO_Init ( GPIOA,
= GPIO_Pin_9 ; // TX GPIO
= GPIO_Speed_50MHz ;
= GPIO_Mode_AF_PP ;
&gpio_i ) ;
gpio_i . GPIO_Pin
gpio_i . GPIO_Speed
gpio_i . GPIO_Mode
GPIO_Init ( GPIOA,
= GPIO_Pin_10 ; // RX GPIO
= GPIO_Speed_50MHz ;
= GPIO_Mode_IN_FLOATING ;
&gpio_i ) ;
27
29
31
33
u s a r t _ i . USART_BaudRate
= 115200; // Configure UART 1152008N1
u s a r t _ i . USART_HardwareFlowControl
= USART_HardwareFlowControl_None ;
u s a r t _ i .USART_Mode
= USART_Mode_Rx | USART_Mode_Tx ;
u s a r t _ i . USART_Parity
= USART_Parity_No ;
u s a r t _ i . USART_StopBits
= USART_StopBits_1 ;
u s a r t _ i . USART_WordLength
= USART_WordLength_8b ;
35
37
39
usart_c . USART_Clock
usart_c .USART_CPHA
usart_c .USART_CPOL
usart_c . USART_LastBit
41
43
45
= USART_Clock_Enable ;
= USART_CPHA_1Edge ;
= USART_CPOL_Low ;
= USART_LastBit_Disable ;
47
}
49
59
61
}
63
15