# Driver cheat sheet ## GPIO Ne pas oublier de toujours activer la clock pour le driver concerné. Dans le cas du GPIO il faut activer celui pour GPIO_X, le registre est dans **RCC->APBXENR** Dans notre cas chaque GPIO est dans APB2ENR (page 112 de [Reference Manual](../assets/cd00171190-stm32f101xx-stm32f102xx-stm32f103xx-stm32f105xx-and-stm32f107xx-advanced-armbased-32bit-mcus-stmicroelectronics.pdf)) : Des variables sont disponibles comme *RCC_APB2ENR_IOPAEN* --- Par la suite il faut choisir quelle pin activer dans le GPIO et en quel mode. Tout cela se passe dans le registre CR ainsi que ODR pour un GPIO Précis. ODR lui va permettre de sélectionner le pull-up/pull-down. Voici le registre : ![ODR](../assets/odr.png) Pour sélectionner le mode, cela se passe dans le registre CR L/H : ![CRLH](../assets/crl.PNG) Attention pour les pins > 7 -> Il faut aller sur le registre high, donc CRH, qui suit la même logique que ce dernier, mais à la différence que celui-ci commence par le bit 8. Il suffit donc avec tous ces registres de suivre le tableau **Figure 20** Sur les différents modes : ![CRLH](../assets/table20_portbit.PNG) L'un des meilleurs moyens pour respecter ce dernier est donc de faire une énumération avec le configuration mode voulu. Comme ça plus besoin de chercher les bons bits. Pour les bits MODE, il suffit de mettre à 0 pour Input, et n'importe quelle autre variable pour Output. Ensuite il faut modifier en conséquence CNF\[1:0], soit le tableau suivant : |Configuration Name|Bits sets| |:-:|---| |In_Floating|0x04| |In_PullDown|0x08| |In_PullUp|0xF8 *(normalement 0x08, mais ici différencié)*| |In_Analog|0x00| |Out_PullUp|0x01| |Out_OD|0x05| |AltOut_Ppull|0x09| |AltOut_OD|0x0d| Tout ces defines doivent être décalés de 4 \* PinNumber. --- Pour ensuite set ou reset ces pins il suffit d'utiliser les deux registres suivants : - BSRR pour set -> 1 décalé de la pin - BRR pour reset -> 1 décalé de la pin Pour observer ces dernières, le registre IDR est le plus intéressant : ```c char gpioRead = (GPIO->IDR & (0x1 << GPIO_Pin)) > 0; ``` ## Timer Dans le cas du Timer il faut activer celui pour TIMXEN, le registre est dans **RCC->APBXENR**. Pour le timer 1 il se trouve dans APB2ENR, et pour les autres dans APB1ENR. --- Il suffit ensuite de régler le PSC et l'ARR pour pouvoir obtenir l'horloge de notre choix sur un timer donné. Le PSC permet de diviser la clock par un certain nombre en respectant cette formule : ``` fCKPSC/PSC+1 = fCKCNT ``` Ensuite en fonction du Time-base unit différents modes sont possible pour ARR, le registre de comptage va s'arrêter de compter à partir de cette valeur ARR. Mais le signal renvoyé par la clock, ou même le flag du timer ne répondra pas de la même manière. Le mode par défaut est donc celui du change on reset. pour trouver la fréquence associée il nous suffit de faire : ``` fCKCNT/ARR+1 = CK_ARR ``` Au final les deux registres étant sur 16 bits, il est possible d'avoir une précision de la division à 32 bits/ ## Interruption Les interruptions doivent être activées de manières différente pour chaque module, mais cela dit il reste quelques similaritées sur le module NVIC qui doit être correctement configuré pour un module donné. Il faut tout d'abord activer l'interruption du côté du module et ensuite modifier la table des vecteurs du NVIC. La première est celle des prioritées, trouvable dans le [Manuel de Référence RM008](../assets/cd00171190-stm32f101xx-stm32f102xx-stm32f103xx-stm32f105xx-and-stm32f107xx-advanced-armbased-32bit-mcus-stmicroelectronics.pdf) page 197, la second e est l'ISER qui permet la réecriture des fonction d'IRQ trouvable dans le [Manuel de programmation PM0056](../assets/New_Programming_Manual_CortexM3.pdf) page 119. ```c int iserRegister = 0; //A voir par rapport au manue lde reference RM008 -> emplacement de la table uint32_t IRQNumber = GetInterruptNum(); //XXX_IRQn NVIC->IP[IRQNumber] |= (Prio << 0x4); NVIC->ISER[iserRegister] |= (0x1<<(IRQNumber-(32*iserRegister))); ``` Enfin, une fonction nommée XXX_IRQHandler sera appelée à l'interruption, il suffiera de réecrire cette dernière pour qu'elle soit active. *NB : Il est important de remettre le flag d'interruption à 0 pour relancer ce dernier.* ### Timer Interruption Le registre pour l'activation de l'interruption est dans TimerX_DIER, sur le bit 0 nommé UIE (Update Interrupt Enable). Le flag d'interruption est UIF. ### UART Interruption Le registre pour l'activation de l'interruption est dans USART_CR1, sur le bit 5 (RXNEIE pour la recepetion) et 7 (TXEIE pour la transmission). Le flag d'intteruption est . ## PWM Pour activer le mode PWM il existe un registre pour chacun des timers permettant d'activer un mode pwm précis. Ce dernier est présent dans le registre CCMRx. Les bits qui nous intéresse sont OCXM. Il existe différents modes pouvant être trouvés page 414 du [Reference Manual](../assets/cd00171190-stm32f101xx-stm32f102xx-stm32f103xx-stm32f105xx-and-stm32f107xx-advanced-armbased-32bit-mcus-stmicroelectronics.pdf). Ici nous utiliseront le même car il est simple : - 110 : **PWM Mode 1**, tant que TIMx_CNT < TIMx_CCRX le channel est actif. CCMR2 possède les channels 3 et 4, et CCMR1 1 et 2. Tous sont utilisable pour chaque Timer. --- Le CCRX (Capture/Compare Register) est un registre de 16 bit qui va déterminer pour un mode de PWM donné le moment où le timer renverra 1 ou 0. Cette variable peut être directement liée à l'ARR : ce qui permet de régler l'alpha d'un PWM directement. Et finalement pour activer ce registre le Timer possède un registre nommé CCER ![ODR](../assets/ccer.png) Ce dernier permet d'activer avec CCXE le registre précedemment paramétré. --- Une GPIO est ainsi associé à chaque PIN. Pour la retrouver il suffit de se rendre à la page 28 du [Manuel F103RB](../assets/STM32F103RB-3.pdf) et voir quelle pin est associée à quel channel de timer. Il suffit de mettre cette dernière en AltOutPpull. ## UART Dans le cas de l'UART il faut activer celui pour USARTXEN, le registre est dans **RCC->APBXENR**. Pour l'USART 1 il se trouve dans APB2ENR, et pour les autres dans APB1ENR. --- Après cela il suffit de régler le registre BRR. C'est un registre de 16 bits qui permet de calculer le baud rate. Il existe une méthode de calcul avec le chiffre après la virgule mais il est ici inutile de l'utiliser. Il suffit de faire : ``` BRR=f_CLK/BaudRate ``` A noter que le f_CLK est différent en fonction de l'U(S)ART choisi. Ici nous avons retenu que : |UART Channel|f_CLK| |:-:|---| |1|72 MHz| |2|36 MHz| |3|36 MHz| *Ces données sont trouvables dans le schéma de câblage des UARTs* --- Par la suite il faut régler le mode de l'UART, pour cela nous allons nous concentrer sur deux registres : |Registre|Fonctions| |:-:|:--| |CR1|Enable, Taille, Parité, RxD/TxD Enable, Interruption| |CR2|Bits de stop| Voici le registre CR1 de l'UART et quels bits modifier pour chacune des fonctions voulues : ![ODR](../assets/usart_cr1.png) Les registres qui nous intéresse sont donc les suivants : - **UE** : USART Enable, à activer dès le début - **M** : Taille de la donnée, 0->8 bits, 1->9 bits - **PCE** et **PS** : PCE active ou non la parité. Si PCE=1, alors PS détermine le type de parité : 0 pour paire, 1 pour impaire. - **TE** et **RE** : Activation de la transmission et de la reception - **RXNEIE** : Activation de l'interruption pour la reception Pour CR2 tout ce qui nous intéresse sont les bits **STOP** (12 et 13): |STOP \[1:0]|Stop bit| |:-:|---| |00|1| |01|0.5| |10|1.5| |11|2| --- Pour la reception ou la transmission des bits sont associés pour savoir si le uC a bien envoyé ou reçu une donnée depuis le TR/RR (TxD Register, RxD Register) vers le Data Register, Ils sont tous présents dans le SR (Status Register) : ![ODR](../assets/usart_sr.png) - RXNE détermine qu'une donnée est reçue si ce bit est à 1. Après lecture de la donnée dans le DR(Data Register), il faut forcer ce dernier à 0 pour le reset - TXE permet de savoir si le registre TR est vide (ce qui veut dire que la donnée a bien été envoyée). - TC permet de savoir si le dernier bit de stop a bien été mis dans le TR. *NB : Il est préférable d'utiliser TXE pour l'envoi de donnée. Ces trois bits fonctionnent aussi en interruption* --- Une GPIO est ainsi associé à chaque PIN. Pour la retrouver il suffit de se rendre à la page 28 du [Manuel F103RB](../assets/STM32F103RB-3.pdf) et voir quelle pin est associée à quel USART Tx/Rx. Par la suite il est conseillé de mettre les différentes pins dans ces modes : - RXD : In Floating/In Pull up (pour un RaspberryPi par exemple) - TXD : AltOut Push Pull