[Из песочницы] Беспроводная отладка STM32

Хочу рассказать о необычном использовании ESP8266 в качестве посредника между STM32 и openOCD. У этого способа довольно много недостатков и его применение может быть вызвано только невозможностью использования обычного (проводного) средства отладки.

Плюс у этого способа один и он очевиден, поэтому перейду сразу к недостаткам:

  1. Требуется патчить openOCD
  2. Необходимо изменить прошивку в ESP8266
  3. Низкая скорость работы


Как это работает. В openOCD реализована поддержка протокола SWD, кроме того там есть драйвер под названием remote_bitbang. Из названия видно, что логические уровни просто передаются числами 1 и 0 и далее отправляются по сети.

Приемник (в нашем случае ESP8266) должен в соответствие этим числам выставить на выводах соответствующий уровень. К сожалению в remote_bitbang отсутствует поддержка SWD, однако добавить ее туда совсем не трудно:

Вот небольшой патч
--- remote_bitbang.c      2016-10-31 11:06:57.812267924 +0600
+++ remote_bitbang.c    2016-10-31 12:33:57.921692808 +0600
@@ -120,11 +120,25 @@
        remote_bitbang_putc(c);
 }
 
+static int remote_bitbang_swdio_read (void)
+{
+       remote_swd_putc ('R');
+       return remote_bitbang_rread ();
+}
+
+static void remote_bitbang_swdio_drive (bool is_output)
+{
+       char c = is_output ? 'o' : 'i';
+       remote_bitbang_putc (c);
+}
+
 static struct bitbang_interface remote_bitbang_bitbang = {
        .read = &remote_bitbang_read,
        .write = &remote_bitbang_write,
        .reset = &remote_bitbang_reset,
        .blink = &remote_bitbang_blink,
+       .swdio_read = &remote_bitbang_swdio_read,
+       .swdio_drive = &remote_bitbang_swdio_drive,     
 };
 
 static int remote_bitbang_init_tcp(void)
@@ -271,10 +285,14 @@
        COMMAND_REGISTRATION_DONE,
 };
 
+static const char * const remote_bitbang_transport[] = { "jtag", "swd", NULL };
+
 struct jtag_interface remote_bitbang_interface = {
        .name = "remote_bitbang",
+       .transports = remote_bitbang_transport,
        .execute_queue = &bitbang_execute_queue,
        .commands = remote_bitbang_command_handlers,
+       .swd = &bitbang_swd,
        .init = &remote_bitbang_init,
        .quit = &remote_bitbang_quit,
 };



Далее нам нужно изменить прошивку ESP8266, чтобы он понимал команды, поступающие от openOCD. Для этой цели я воспользовался открытым SDK esp-open-rtos. Весь код прошивки я приводить не буду — он довольно объемистый, приведу только его часть, касающуюся обработки данных поступающих от openOCD.

Спойлер
#define SWCLK                         0
#define SWDIO                           2

IRAM void openocd_handler (void *pvParameters)
{
        struct netconn *nc = (struct netconn *) pvParameters;
        struct netbuf *rbuf = NULL;
        char *rx_buf;
        char d, r;
        err_t err;
        uint16_t len;
        uint16_t i;
        
        gpio_set_pullup (SWCLK, false, false);
        gpio_set_pullup (SWDIO, false, false);
        gpio_enable (SWCLK, GPIO_OUTPUT);
        gpio_enable (SWDIO, GPIO_OUTPUT);
        
        while (1)
        {
                if ((err = netconn_recv (nc, &rbuf)) != ERR_OK) {
                        printf ("R ERROR %d\n", err);
                        return;
                }
                
                netbuf_data (rbuf, (void **) &rx_buf, &len);    
                
                for (i = 0; i < len; i++)
                {
                        switch (rx_buf [i])
                        {
                        case 'Q':               // Quit
                                netconn_disconnect (nc);
                                return;
                        
                        case '0'...'7':
                                d = rx_buf [i] - '0';
                                gpio_write (SWDIO, (d & 0x1));
                                gpio_write (SWCLK, !!(d & 0x4));                                                                
                                break;
                        
                        case 'i':
                                gpio_enable (SWDIO, GPIO_INPUT);
                                break;
                        
                        case 'o':
                                gpio_enable (SWDIO, GPIO_OUTPUT);
                                break;
                        
                        case 'R':               // Writeback
                                r = ((char) gpio_read (SWDIO)) + '0';
                                netconn_write (nc, &r, 1, NETCONN_COPY);
                                break; 
                        }
                }
                
                netbuf_delete (rbuf);
        }
}



Полный исходный код можно взять здесь.

Я использую ESP-01. У нее две свободные ноги GPIO-0 и GPIO-2, причем при включении на 2-й ноге должен быть высокий уровень иначе контроллер войдет в режим загрузчика. Поэтому желательно подтянуть ножку к питанию через 10к резистор.

Что касается низкой скорости работы. Да, по шагам он ходит довольно уныло, но залить прошивку, поставить прерывание или прочитать переменную можно.

Теоретически, если портировать openOCD на ESP8266 можно добиться скорости работы сравнимой с st-link, но это я оставляю сделать читателям.

Надеюсь, кому-то мог быть полезен.

© Geektimes