Comment arrêter d'écrire le firmware des microcontrôleurs. Nous commençons à vivre ...


Et encore une fois, nous découvrons comment ne pas écrire de firmware pour les microcontrôleurs. L'article précédent a suscité beaucoup d'émotions chez les gens et, il me semble, peu de gens ont compris et, peut-être, on m'a mal expliqué pourquoi tout cela a commencé.


J'ai donc préparé un exemple .


Bien qu'il ne s'agisse que d'un échantillon modifié de DMA_Polling de la bibliothèque de périphériques standard.


Mais c'est l'avantage de cette approche, que vous pouvez utiliser tous les développements à partir du code exécuté sur le microcontrôleur, y compris les bibliothèques du fabricant MK comme HAL ou Standard Peripherals Library. Et cela devrait être juste pour tout contrôleur prenant en charge openOCD - au moins STM32, Atmel, PIC32 et autres sur la liste . Dans le même temps, nous pouvons utiliser toutes les bibliothèques du PC hôte, ainsi que les nouvelles normes de langage C ++. Et si vous écrivez des wrappers, vous pouvez en général utiliser n'importe quelle langue. Mais je n'ai pas beaucoup compliqué ici. Je viens de décider de montrer les fonctionnalités et fonctionnalités de base.


Dans l'exemple, bien sûr, nous allons faire clignoter la LED. Et également envoyer des données sur UART et sur un autre UART pour les recevoir en utilisant DMA. L'utilisation de DMA donne un énorme bonus. Souvent, il sera possible de se débarrasser des interruptions que nous ne pouvons pas utiliser ici, et de l'interrogation, qui, en raison de mon débogueur, est très lente, mais encore moins de temps pour capturer des données sur les interfaces. Et aussi générer rapidement. Par conséquent, il est assez simple de créer un générateur de signal programmable et un renifleur de diverses interfaces.


L'équipement sur lequel nous allons tester reste du temps du premier article


image
Ici, j'ai connecté le câblage blanc UART1 (broche PA9) avec Rx UART2 (broche PA3).


Si vous regardez le code
const char * message = "AddressIntercept PinTool UART DMA example"; int main() { sizeMemoryTranslate_t s = 0; memoryTranslate *p = getMemoryMap(&s); pAddrPERIPH = p[0].start_addr; pAddrSRAM = p[1].start_addr; init(); RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE); GPIO_InitTypeDef gpio; gpio.GPIO_Pin = GPIO_Pin_13; gpio.GPIO_Speed = GPIO_Speed_50MHz; gpio.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_Init(GPIOC, &gpio); const size_t _SIZE_MESSAGE = strlen(message); printf("sending message "); for (int i = 0; i < _SIZE_MESSAGE; i++) { /* Send one byte from USARTy to USARTz */ USART_SendData(USARTy, message[i]); GPIO_SetBits(GPIOC, GPIO_Pin_13); /* Loop until USARTy DR register is empty */ while (USART_GetFlagStatus(USARTy, USART_FLAG_TXE) == RESET); printf("."); fflush(stdout); GPIO_ResetBits(GPIOC, GPIO_Pin_13); } printf("\n"); printf("qty of sent bytes %d\n", strlen(message)); const uint16_t rec = DMA_GetCurrDataCounter(USARTz_Rx_DMA_Channel); printf("qty of received byte using DMA : %d\n", sizeDMAbuf - rec); printf("read message from buffer DMA : "); const uint8_t *pM = (uint8_t *)pAddrSRAM; for (int r = 0; r < _SIZE_MESSAGE; r++) { printf("%c", pM[r]); fflush(stdout); } printf("\n"); assert(strncmp(message, (const char *)pM, _SIZE_MESSAGE) == 0); printf("Received and sent bytes are equal!\n"); return 0; } 

Vous pouvez voir que, à l'exception de notre fonction de conversion des adresses et des fonctions de la bibliothèque standard, tout le reste a été pris par SPL de ST, en principe il était possible d'utiliser des fonctions HAL. Mais je connais mieux le bon vieux SPL.


Comment assembler et gérer tout cela


Voici un exemple pour un PC avec Ubuntu 16.04 64 bits:


Vous devez d'abord télécharger Pintool v3.7


Le déballage est pratique, vous pouvez soit définir la variable PIN_ROOT pour construire le client PinTool, soit localiser simplement notre client dans


 pin-3.7-97619-g0d0c92f4f-gcc-linux/source/tools/ 

Je fais la deuxième façon


 cd pin-3.7-97619-g0d0c92f4f-gcc-linux/source/tools/ git clone git@github.com:ser-mk/AddressIntercept.git cd AddressIntercept 

Ensuite, vous devez créer un client 32 bits


 make TARGET=ia32 

Le binaire sera ici obj-ia32 / addrIntercept.so. 32 bits est nécessaire, car dans ARM ortex une telle taille d'adresse.


Vous pouvez maintenant collecter l'exemple lui-même. Je le copie directement dans le dossier du client pintool


 cd pin-3.7-97619-g0d0c92f4f-gcc-linux/source/tools/AddressIntercept Git clone https://github.com/ser-mk/addrIntercept-example-UART-DMA Cd addrIntercept-example-UART-DMA Make 

Et nous obtenons le binaire dans le répertoire test.elf. Pour plus de simplicité d'expérience, je mettrai le fichier dans le répertoire de notre client Pintool AddressIntercept


Avant de tout commencer, nous aurions besoin de créer des FIFO nommés pour communiquer avec le client OpenOCD


 cd pin-3.7-97619-g0d0c92f4f-gcc-linux/source/tools/AddressIntercept mkfifo in.fifo out.fifo 

in.fifo out.fifo - noms par défaut pour nos clients, vous pouvez donner d'autres noms, mais ils devront ensuite être spécifiés explicitement lors du démarrage des clients.


Commençons le client openOCD, dans mon cas, je dois lui passer le serveur ip openOCD, ce sera 192.168.0.111, le port quittera la norme 6666, donc je ne le spécifie pas.


Alors, courez dans l'ordre


 cd pin-3.7-97619-g0d0c92f4f-gcc-linux/source/tools/AddressIntercept python3.5m OCDclient.py -ip 192.168.0.111 & ../../../pin -t obj-ia32/addrIntercept.so -- addrIntercept-example-UART-DMA/test.elf 

Et la conclusion devrait être la suivante:


image


J'espère un exemple illustratif. Déjà une preuve de concept qui peut être utilisée.


De plus, tout devrait fonctionner, y compris sur MacOS et Windows (ici, vous devrez peut-être modifier le travail avec fifo nommé ou le remplacer par ce qui est dans les "fenêtres").


De plus, dans les articles suivants, si cela est intéressant, vous pouvez parler de REPL comme sur le GIF de l'article précédent et d'autres façons d'intercepter des adresses, sans limiter la plate-forme Intel.

Source: https://habr.com/ru/post/fr434080/


All Articles