How to stop writing firmware for microcontrollers. We are starting to live ...


    And again, we figure out how not to write firmware for microcontrollers. The previous article aroused a lot of emotions in people and, it seems to me, few people understood and, perhaps, it was poorly explained to me why all this was started.


    Therefore, I prepared an example .


    Although this is just a tweaked sample of DMA_Polling from the Standard Peripherals Library.


    But this is the advantage of such an approach that you can use all the developments from the code executed on the microcontroller, including libraries from the manufacturer of the MK type HAL or Standard Peripherals Library. And this should be fair for any controller that supports openOCD - at least STM32, Atmel, PIC32 and others on the list . At the same time, we can use all the libraries of the host PC, as well as use the new C ++ language standards. And if you write wrappers, then in general you can use any language. But I didn’t complicate much here. I just decided to show the basic functionality and features.


    In the example, of course, we will blink the LED. And also send data on UART and on another UART to receive them using DMA. Using DMA gives a huge bonus. Often it will be possible to get rid of interrupts that we cannot use here, and polling, which, due to my debugger, is very slow, but still less time to capture data on interfaces. And also quickly generate. Therefore, it is quite simple to make a programmable signal generator and a sniffer of various interfaces.


    The equipment on which we will test remains from the time of the first article


    image
    Here I connected the white wiring Тх UART1 (PA9 pin) with Rx UART2 (PA3 pin).


    If you look at the 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;
    }

    You can see that, with the exception of our function of converting addresses and functions from the standard library, everything else is taken from SPL from ST, in principle, it was possible to use from HAL functions. But I’m more familiar with the good old SPL.


    How to assemble and run it all


    This is an example for a PC with Ubuntu 16.04 64-bit:


    First you need to download Pintool v3.7


    Unpacking is convenient, then you can either define the PIN_ROOT variable to build the PinTool client or simply locate our client in


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

    I do the second way


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

    Next, you need to build a 32-bit client


    make TARGET=ia32

    The binary will be here obj-ia32 / addrIntercept.so. 32-bit is required, because in ARM Сortex such an address size.


    Now you can collect the example itself. I copy it directly to the folder to the 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

    And we get the binary in the test.elf directory. Further for simplicity of experiment, I will put the file in the directory of our Pintool client AddressIntercept


    Before starting everything, we would need to create named FIFOs to communicate with the OpenOCD client


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

    in.fifo out.fifo - default names for our clients, you can give other names, but then they will have to be specified explicitly when starting clients.


    Run the openOCD client, in my case it needs to pass the ip openOCD server ip, it will be 192.168.0.111, the port will leave the standard 6666, so I do not specify it.


    So, run in order


    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

    And the conclusion should be like this:


    image


    I hope an illustrative example. Already quite a proof of concept that can be used.


    Moreover, everything should work, including on MacOS and Windows (here, you may have to tweak the work with named fifo or replace it with what is in the "windows").


    Further, in the following articles, if it is interesting, you can talk about REPL as on the GIF from the previous article and other ways of intercepting addresses, without limitation by the Intel platform.


    Also popular now: