
Und wieder finden wir heraus, wie man keine Firmware für Mikrocontroller schreibt. Der vorige Artikel hat viele Emotionen bei Menschen geweckt, und es scheint mir, dass nur wenige Menschen verstanden haben, und vielleicht wurde mir schlecht erklärt, warum all dies begonnen wurde.
Deshalb habe ich ein Beispiel vorbereitet.
Dies ist zwar nur ein optimiertes Beispiel für DMA_Polling aus der Standard Peripherals Library.
Dies ist jedoch der Vorteil dieses Ansatzes, dass Sie alle Entwicklungen aus dem auf dem Mikrocontroller ausgeführten Code verwenden können, einschließlich Bibliotheken des Herstellers MK wie HAL oder Standard Peripherals Library. Und dies sollte für jeden Controller fair sein, der openOCD unterstützt - zumindest STM32, Atmel, PIC32 und andere auf der Liste . Gleichzeitig können wir alle Bibliotheken des Host-PCs sowie die neuen C ++ - Sprachstandards verwenden. Und wenn Sie Wrapper schreiben, können Sie im Allgemeinen jede Sprache verwenden. Aber ich habe hier nicht viel kompliziert. Ich habe mich gerade entschlossen, die grundlegenden Funktionen und Merkmale zu zeigen.
Im Beispiel blinken wir natürlich die LED. Senden Sie außerdem Daten auf UART und einem anderen UART, um sie über DMA zu empfangen. Die Verwendung von DMA bietet einen enormen Bonus. Oft ist es möglich, Interrupts zu entfernen, die wir hier nicht verwenden können, und Abfragen, die aufgrund meines Debuggers sehr langsam sind, aber immer noch weniger Zeit zum Erfassen von Daten auf Schnittstellen benötigen. Und auch schnell generieren. Daher ist es ziemlich einfach, einen programmierbaren Signalgenerator und einen Sniffer verschiedener Schnittstellen herzustellen.
Die Ausrüstung, an der wir testen werden, bleibt ab dem Zeitpunkt des ersten Artikels erhalten

Hier habe ich die weiße Verkabelung UART1 (PA9-Pin) mit Rx UART2 (PA3-Pin) verbunden.
Wenn Sie sich den Code ansehenconst 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++) { USART_SendData(USARTy, message[i]); GPIO_SetBits(GPIOC, GPIO_Pin_13); 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; }
Sie sehen, dass mit Ausnahme unserer Funktion zum Konvertieren von Adressen und Funktionen aus der Standardbibliothek alles andere aus der SPL von ST übernommen wurde. Grundsätzlich war es möglich, diese aus der HAL-Funktion zu verwenden. Aber ich bin an die gute alte SPL gewöhnt.
Wie man alles zusammenbaut und laufen lässt
Dies ist ein Beispiel für einen PC mit Ubuntu 16.04 64-Bit:
Zuerst müssen Sie Pintool v3.7 herunterladen
Das Entpacken ist praktisch. Sie können entweder die Variable PIN_ROOT definieren, um den PinTool-Client zu erstellen, oder einfach unseren Client in suchen
pin-3.7-97619-g0d0c92f4f-gcc-linux/source/tools/
Ich mache den zweiten Weg
cd pin-3.7-97619-g0d0c92f4f-gcc-linux/source/tools/ git clone git@github.com:ser-mk/AddressIntercept.git cd AddressIntercept
Als Nächstes müssen Sie einen 32-Bit-Client erstellen
make TARGET=ia32
Die Binärdatei wird hier obj-ia32 / addrIntercept.so sein. 32-Bit ist erforderlich, da in ARM ortex eine solche Adressgröße vorliegt.
Jetzt können Sie das Beispiel selbst sammeln. Ich kopiere es direkt in den Ordner auf den Pintool-Client
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
Und wir bekommen die Binärdatei im Verzeichnis test.elf. Zur Vereinfachung des Experiments werde ich die Datei im Verzeichnis unseres Pintool-Clients AddressIntercept ablegen
Bevor wir alles starten, müssen wir benannte FIFOs erstellen, um mit dem OpenOCD-Client zu kommunizieren
cd pin-3.7-97619-g0d0c92f4f-gcc-linux/source/tools/AddressIntercept mkfifo in.fifo out.fifo
in.fifo out.fifo - Standardnamen für unsere Clients. Sie können andere Namen angeben, diese müssen jedoch beim Starten von Clients explizit angegeben werden.
Führen Sie den openOCD-Client aus. In meinem Fall muss er die IP-Adresse des OpenOCD-Servers übergeben. Er lautet 192.168.0.111. Der Port verlässt den Standard 6666, daher gebe ich ihn nicht an.
Also in der richtigen Reihenfolge laufen
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
Und die Schlussfolgerung sollte so lauten:

Ich hoffe ein anschauliches Beispiel. Schon ein ziemlicher Proof of Concept, der verwendet werden kann.
Darüber hinaus sollte alles funktionieren, auch unter MacOS und Windows (hier müssen Sie möglicherweise die Arbeit mit dem Namen fifo optimieren oder durch das ersetzen, was sich in den "Fenstern" befindet).
Wenn es interessant ist, können Sie in den folgenden Artikeln über REPL wie im GIF aus dem vorherigen Artikel und andere Möglichkeiten zum Abfangen von Adressen sprechen, ohne die Intel-Plattform einzuschränken.