From 048e8447a58d996e7be32ddc17194c591c1dc176 Mon Sep 17 00:00:00 2001 From: Gareth McMullin Date: Fri, 13 Oct 2017 08:58:37 +1300 Subject: [PATCH 1/6] target: Only support buffered flash writes --- src/target/efm32.c | 4 +--- src/target/kinetis.c | 1 - src/target/lmi.c | 1 - src/target/lpc11xx.c | 3 +-- src/target/lpc15xx.c | 3 +-- src/target/lpc_common.c | 5 +---- src/target/nrf51.c | 5 ++--- src/target/sam3x.c | 9 ++------- src/target/sam4l.c | 8 +++----- src/target/samd.c | 5 +---- src/target/stm32f1.c | 1 - src/target/stm32f4.c | 1 - src/target/stm32l0.c | 5 +---- src/target/stm32l4.c | 4 +--- src/target/target.c | 26 +++++++++++++------------- src/target/target_internal.h | 10 +--------- 16 files changed, 28 insertions(+), 63 deletions(-) diff --git a/src/target/efm32.c b/src/target/efm32.c index 97dc2ebc..a67abed7 100644 --- a/src/target/efm32.c +++ b/src/target/efm32.c @@ -239,9 +239,7 @@ static void efm32_add_flash(target *t, target_addr addr, size_t length, f->length = length; f->blocksize = page_size; f->erase = efm32_flash_erase; - f->write = target_flash_write_buffered; - f->done = target_flash_done_buffered; - f->write_buf = efm32_flash_write; + f->write = efm32_flash_write; f->buf_size = page_size; target_add_flash(t, f); } diff --git a/src/target/kinetis.c b/src/target/kinetis.c index b65366c7..037adf3b 100644 --- a/src/target/kinetis.c +++ b/src/target/kinetis.c @@ -94,7 +94,6 @@ static void kl_gen_add_flash(target *t, f->erase = kl_gen_flash_erase; f->write = kl_gen_flash_write; f->done = kl_gen_flash_done; - f->align = 4; f->erased = 0xff; target_add_flash(t, f); } diff --git a/src/target/lmi.c b/src/target/lmi.c index ed54d57a..e0ecd685 100644 --- a/src/target/lmi.c +++ b/src/target/lmi.c @@ -65,7 +65,6 @@ static void lmi_add_flash(target *t, size_t length) f->blocksize = 0x400; f->erase = lmi_flash_erase; f->write = lmi_flash_write; - f->align = 4; f->erased = 0xff; target_add_flash(t, f); } diff --git a/src/target/lpc11xx.c b/src/target/lpc11xx.c index 248e7ee7..eb9919b2 100644 --- a/src/target/lpc11xx.c +++ b/src/target/lpc11xx.c @@ -40,7 +40,7 @@ void lpc11xx_add_flash(target *t, uint32_t addr, size_t len, size_t erasesize) struct lpc_flash *lf = lpc_add_flash(t, addr, len); lf->f.blocksize = erasesize; lf->f.buf_size = IAP_PGM_CHUNKSIZE; - lf->f.write_buf = lpc_flash_write_magic_vect; + lf->f.write = lpc_flash_write_magic_vect; lf->iap_entry = IAP_ENTRYPOINT; lf->iap_ram = IAP_RAM_BASE; lf->iap_msp = IAP_RAM_BASE + MIN_RAM_SIZE - RAM_USAGE_FOR_IAP_ROUTINES; @@ -122,4 +122,3 @@ lpc11xx_probe(target *t) return false; } - diff --git a/src/target/lpc15xx.c b/src/target/lpc15xx.c index 4e362e2c..7b86d42f 100644 --- a/src/target/lpc15xx.c +++ b/src/target/lpc15xx.c @@ -40,7 +40,7 @@ void lpc15xx_add_flash(target *t, uint32_t addr, size_t len, size_t erasesize) struct lpc_flash *lf = lpc_add_flash(t, addr, len); lf->f.blocksize = erasesize; lf->f.buf_size = IAP_PGM_CHUNKSIZE; - lf->f.write_buf = lpc_flash_write_magic_vect; + lf->f.write = lpc_flash_write_magic_vect; lf->iap_entry = IAP_ENTRYPOINT; lf->iap_ram = IAP_RAM_BASE; lf->iap_msp = IAP_RAM_BASE + MIN_RAM_SIZE - RAM_USAGE_FOR_IAP_ROUTINES; @@ -77,4 +77,3 @@ lpc15xx_probe(target *t) return false; } - diff --git a/src/target/lpc_common.c b/src/target/lpc_common.c index 63d844e5..bdae7e19 100644 --- a/src/target/lpc_common.c +++ b/src/target/lpc_common.c @@ -40,9 +40,7 @@ struct lpc_flash *lpc_add_flash(target *t, target_addr addr, size_t length) f->start = addr; f->length = length; f->erase = lpc_flash_erase; - f->write = target_flash_write_buffered; - f->done = target_flash_done_buffered; - f->write_buf = lpc_flash_write; + f->write = lpc_flash_write; f->erased = 0xff; target_add_flash(t, f); return lf; @@ -148,4 +146,3 @@ int lpc_flash_write_magic_vect(struct target_flash *f, } return lpc_flash_write(f, dest, src, len); } - diff --git a/src/target/nrf51.c b/src/target/nrf51.c index 91f1d43f..4f2ab449 100644 --- a/src/target/nrf51.c +++ b/src/target/nrf51.c @@ -97,7 +97,6 @@ static void nrf51_add_flash(target *t, f->blocksize = erasesize; f->erase = nrf51_flash_erase; f->write = nrf51_flash_write; - f->align = 4; f->erased = 0xff; target_add_flash(t, f); } @@ -112,7 +111,7 @@ bool nrf51_probe(target *t) case 0x0020: /* nRF51822 (rev 1) CEAA BA */ case 0x0024: /* nRF51422 (rev 1) QFAA C0 */ case 0x002A: /* nRF51822 (rev 2) QFAA FA0 */ - case 0x004A: /* nRF51822 (rev 3) QFAA G1 */ + case 0x004A: /* nRF51822 (rev 3) QFAA G1 */ case 0x002D: /* nRF51422 (rev 2) QFAA DAA */ case 0x002E: /* nRF51422 (rev 2) QFAA E0 */ case 0x002F: /* nRF51822 (rev 1) CEAA B0 */ @@ -129,7 +128,7 @@ bool nrf51_probe(target *t) case 0x0079: /* nRF51822 (rev 3) CEAA E0 */ case 0x007A: /* nRF51422 (rev 3) CEAA C0 */ case 0x008F: /* nRF51822 (rev 3) QFAA H1 See https://devzone.nordicsemi.com/question/97769/can-someone-conform-the-config-id-code-for-the-nrf51822qfaah1/ */ - case 0x00D1: /* nRF51822 (rev 3) QFAA H2 */ + case 0x00D1: /* nRF51822 (rev 3) QFAA H2 */ t->driver = "Nordic nRF51"; target_add_ram(t, 0x20000000, 0x4000); nrf51_add_flash(t, 0x00000000, 0x40000, NRF51_PAGE_SIZE); diff --git a/src/target/sam3x.c b/src/target/sam3x.c index 0a96308a..48403d66 100644 --- a/src/target/sam3x.c +++ b/src/target/sam3x.c @@ -131,9 +131,7 @@ static void sam3_add_flash(target *t, f->length = length; f->blocksize = SAM3_PAGE_SIZE; f->erase = sam3_flash_erase; - f->write = target_flash_write_buffered; - f->done = target_flash_done_buffered; - f->write_buf = sam3x_flash_write; + f->write = sam3x_flash_write; f->buf_size = SAM3_PAGE_SIZE; sf->eefc_base = eefc_base; sf->write_cmd = EEFC_FCR_FCMD_EWP; @@ -149,9 +147,7 @@ static void sam4_add_flash(target *t, f->length = length; f->blocksize = SAM4_PAGE_SIZE * 8; f->erase = sam4_flash_erase; - f->write = target_flash_write_buffered; - f->done = target_flash_done_buffered; - f->write_buf = sam3x_flash_write; + f->write = sam3x_flash_write; f->buf_size = SAM4_PAGE_SIZE; sf->eefc_base = eefc_base; sf->write_cmd = EEFC_FCR_FCMD_WP; @@ -355,4 +351,3 @@ static bool sam3x_cmd_gpnvm_set(target *t, int argc, char *argv[]) return true; } - diff --git a/src/target/sam4l.c b/src/target/sam4l.c index cdb90726..54bcc52d 100644 --- a/src/target/sam4l.c +++ b/src/target/sam4l.c @@ -173,9 +173,7 @@ static void sam4l_add_flash(target *t, uint32_t addr, size_t length) f->length = length; f->blocksize = SAM4L_PAGE_SIZE; f->erase = sam4l_flash_erase; - f->write = target_flash_write_buffered; - f->done = target_flash_done_buffered; - f->write_buf = sam4l_flash_write_buf; + f->write = sam4l_flash_write_buf; f->buf_size = SAM4L_PAGE_SIZE; f->erased = 0xff; /* add it into the target structures flash chain */ @@ -238,7 +236,7 @@ bool sam4l_probe(target *t) DEBUG("\nSAM4L: RAM = 0x%x (%dK), FLASH = 0x%x (%dK)\n", (unsigned int) ram_size, (unsigned int) (ram_size / 1024), (unsigned int) flash_size, (unsigned int)(flash_size / 1024)); - + /* enable SMAP if not, check for HCR and reset if set */ sam4l_extended_reset(t); DEBUG("\nSAM4L: SAM4L Selected.\n"); @@ -331,7 +329,7 @@ sam4l_flash_write_buf(struct target_flash *f, target_addr addr, const void *src, uint32_t *src_data = (uint32_t *)src; uint32_t ndx; uint16_t page; - + DEBUG("\nSAM4L: sam4l_flash_write_buf: addr = 0x%08lx, len %d\n", (long unsigned int) addr, (int) len); /* This will fail with unaligned writes, the write_buf version */ page = addr / SAM4L_PAGE_SIZE; diff --git a/src/target/samd.c b/src/target/samd.c index 78618731..bc143b4d 100644 --- a/src/target/samd.c +++ b/src/target/samd.c @@ -350,9 +350,7 @@ static void samd_add_flash(target *t, uint32_t addr, size_t length) f->length = length; f->blocksize = SAMD_ROW_SIZE; f->erase = samd_flash_erase; - f->write = target_flash_write_buffered; - f->done = target_flash_done_buffered; - f->write_buf = samd_flash_write; + f->write = samd_flash_write; f->buf_size = SAMD_PAGE_SIZE; target_add_flash(t, f); } @@ -698,4 +696,3 @@ static bool samd_cmd_ssb(target *t) return true; } - diff --git a/src/target/stm32f1.c b/src/target/stm32f1.c index c9823db3..688ce3ea 100644 --- a/src/target/stm32f1.c +++ b/src/target/stm32f1.c @@ -109,7 +109,6 @@ static void stm32f1_add_flash(target *t, f->blocksize = erasesize; f->erase = stm32f1_flash_erase; f->write = stm32f1_flash_write; - f->align = 2; f->erased = 0xff; target_add_flash(t, f); } diff --git a/src/target/stm32f4.c b/src/target/stm32f4.c index c6a9a5fa..ec5cdc7b 100644 --- a/src/target/stm32f4.c +++ b/src/target/stm32f4.c @@ -161,7 +161,6 @@ static void stm32f4_add_flash(target *t, f->blocksize = blocksize; f->erase = stm32f4_flash_erase; f->write = stm32f4_flash_write; - f->align = 4; f->erased = 0xff; sf->base_sector = base_sector; sf->psize = 32; diff --git a/src/target/stm32l0.c b/src/target/stm32l0.c index ea22cb98..14e42d63 100644 --- a/src/target/stm32l0.c +++ b/src/target/stm32l0.c @@ -237,9 +237,7 @@ static void stm32l_add_flash(target *t, f->length = length; f->blocksize = erasesize; f->erase = stm32lx_nvm_prog_erase; - f->write = target_flash_write_buffered; - f->done = target_flash_done_buffered; - f->write_buf = stm32lx_nvm_prog_write; + f->write = stm32lx_nvm_prog_write; f->buf_size = erasesize/2; target_add_flash(t, f); } @@ -252,7 +250,6 @@ static void stm32l_add_eeprom(target *t, uint32_t addr, size_t length) f->blocksize = 4; f->erase = stm32lx_nvm_data_erase; f->write = stm32lx_nvm_data_write; - f->align = 1; target_add_flash(t, f); } diff --git a/src/target/stm32l4.c b/src/target/stm32l4.c index c5432b49..54d0e545 100644 --- a/src/target/stm32l4.c +++ b/src/target/stm32l4.c @@ -135,9 +135,7 @@ static void stm32l4_add_flash(target *t, f->length = length; f->blocksize = blocksize; f->erase = stm32l4_flash_erase; - f->write = target_flash_write_buffered; - f->done = target_flash_done_buffered; - f->write_buf = stm32l4_flash_write; + f->write = stm32l4_flash_write; f->buf_size = 2048; f->erased = 0xff; sf->bank1_start = bank1_start; diff --git a/src/target/target.c b/src/target/target.c index e433bdbd..7ad57162 100644 --- a/src/target/target.c +++ b/src/target/target.c @@ -26,6 +26,10 @@ target *target_list = NULL; +static int target_flash_write_buffered(struct target_flash *f, + target_addr dest, const void *src, size_t len); +static int target_flash_done_buffered(struct target_flash *f); + target *target_new(void) { target *t = (void*)calloc(1, sizeof(*t)); @@ -138,6 +142,8 @@ void target_add_ram(target *t, target_addr start, uint32_t len) void target_add_flash(target *t, struct target_flash *f) { + if (f->buf_size == 0) + f->buf_size = MIN(f->blocksize, 0x400); f->t = t; f->next = t->flash; t->flash = f; @@ -216,15 +222,7 @@ int target_flash_write(target *t, struct target_flash *f = flash_for_addr(t, dest); size_t tmptarget = MIN(dest + len, f->start + f->length); size_t tmplen = tmptarget - dest; - if (f->align > 1) { - uint32_t offset = dest % f->align; - uint8_t data[ALIGN(offset + tmplen, f->align)]; - memset(data, f->erased, sizeof(data)); - memcpy((uint8_t *)data + offset, src, tmplen); - ret |= f->write(f, dest - offset, data, sizeof(data)); - } else { - ret |= f->write(f, dest, src, tmplen); - } + ret |= target_flash_write_buffered(f, dest, src, tmplen); dest += tmplen; src += tmplen; len -= tmplen; @@ -235,6 +233,9 @@ int target_flash_write(target *t, int target_flash_done(target *t) { for (struct target_flash *f = t->flash; f; f = f->next) { + int tmp = target_flash_done_buffered(f); + if (tmp) + return tmp; if (f->done) { int tmp = f->done(f); if (tmp) @@ -260,8 +261,8 @@ int target_flash_write_buffered(struct target_flash *f, if (base != f->buf_addr) { if (f->buf_addr != (uint32_t)-1) { /* Write sector to flash if valid */ - ret |= f->write_buf(f, f->buf_addr, - f->buf, f->buf_size); + ret |= f->write(f, f->buf_addr, + f->buf, f->buf_size); } /* Setup buffer for a new sector */ f->buf_addr = base; @@ -282,7 +283,7 @@ int target_flash_done_buffered(struct target_flash *f) int ret = 0; if ((f->buf != NULL) &&(f->buf_addr != (uint32_t)-1)) { /* Write sector to flash if valid */ - ret = f->write_buf(f, f->buf_addr, f->buf, f->buf_size); + ret = f->write(f, f->buf_addr, f->buf, f->buf_size); f->buf_addr = -1; free(f->buf); f->buf = NULL; @@ -564,4 +565,3 @@ int tc_system(target *t, target_addr cmd, size_t cmdlen) } return t->tc->system(t->tc, cmd, cmdlen); } - diff --git a/src/target/target_internal.h b/src/target/target_internal.h index 33f16632..0ef0236a 100644 --- a/src/target/target_internal.h +++ b/src/target/target_internal.h @@ -43,13 +43,9 @@ struct target_flash { flash_write_func write; flash_done_func done; target *t; - struct target_flash *next; - int align; uint8_t erased; - - /* For buffered flash */ size_t buf_size; - flash_write_func write_buf; + struct target_flash *next; target_addr buf_addr; void *buf; }; @@ -131,9 +127,6 @@ struct target_s { void target_add_commands(target *t, const struct command_s *cmds, const char *name); void target_add_ram(target *t, target_addr start, uint32_t len); void target_add_flash(target *t, struct target_flash *f); -int target_flash_write_buffered(struct target_flash *f, - target_addr dest, const void *src, size_t len); -int target_flash_done_buffered(struct target_flash *f); /* Convenience function for MMIO access */ uint32_t target_mem_read32(target *t, uint32_t addr); @@ -184,4 +177,3 @@ bool kinetis_probe(target *t); bool efm32_probe(target *t); #endif - From 3e3e4504088ca9f579aaedf3da273af983de0fe1 Mon Sep 17 00:00:00 2001 From: Uwe Bonnes Date: Thu, 26 Oct 2017 19:05:18 +0200 Subject: [PATCH 2/6] cdcacm.c: Use less buffer for the usb_uart buffers and reallocate. With 128 bytes for both usb_uart buffers, traceswo gives errors! Keep the size for the receive buffer and diminisch the transmit buffer, as there is no flow control to the device. Probably related to https://github.com/libopencm3/libopencm3/issues/477 --- src/platforms/common/cdcacm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/platforms/common/cdcacm.c b/src/platforms/common/cdcacm.c index 62cc419b..ccf6706e 100644 --- a/src/platforms/common/cdcacm.c +++ b/src/platforms/common/cdcacm.c @@ -517,7 +517,7 @@ static void cdcacm_set_config(usbd_device *dev, uint16_t wValue) /* Serial interface */ usbd_ep_setup(dev, 0x03, USB_ENDPOINT_ATTR_BULK, - CDCACM_PACKET_SIZE, usbuart_usb_out_cb); + CDCACM_PACKET_SIZE / 2, usbuart_usb_out_cb); usbd_ep_setup(dev, 0x83, USB_ENDPOINT_ATTR_BULK, CDCACM_PACKET_SIZE, usbuart_usb_in_cb); usbd_ep_setup(dev, 0x84, USB_ENDPOINT_ATTR_INTERRUPT, 16, NULL); From 93bc3a155aed37158897d5d24b4070b2e6aaf61b Mon Sep 17 00:00:00 2001 From: Uwe Bonnes Date: Thu, 26 Oct 2017 15:11:55 +0200 Subject: [PATCH 3/6] traceswo: Provide command option for async swo. --- src/command.c | 18 ++++++++++++++---- src/platforms/common/traceswo.h | 2 +- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/src/command.c b/src/command.c index 9594c3a5..648ec882 100644 --- a/src/command.c +++ b/src/command.c @@ -56,7 +56,7 @@ static bool cmd_hard_srst(void); static bool cmd_target_power(target *t, int argc, const char **argv); #endif #ifdef PLATFORM_HAS_TRACESWO -static bool cmd_traceswo(void); +static bool cmd_traceswo(target *t, int argc, const char **argv); #endif #ifdef PLATFORM_HAS_DEBUG static bool cmd_debug_bmp(target *t, int argc, const char **argv); @@ -75,7 +75,7 @@ const struct command_s cmd_list[] = { {"tpwr", (cmd_handler)cmd_target_power, "Supplies power to the target: (enable|disable)"}, #endif #ifdef PLATFORM_HAS_TRACESWO - {"traceswo", (cmd_handler)cmd_traceswo, "Start trace capture" }, + {"traceswo", (cmd_handler)cmd_traceswo, "Start trace capture [(baudrate) for async swo]" }, #endif #ifdef PLATFORM_HAS_DEBUG {"debug_bmp", (cmd_handler)cmd_debug_bmp, "Output BMP \"debug\" strings to the second vcom: (enable|disable)"}, @@ -277,10 +277,20 @@ static bool cmd_target_power(target *t, int argc, const char **argv) #endif #ifdef PLATFORM_HAS_TRACESWO -static bool cmd_traceswo(void) +static bool cmd_traceswo(target *t, int argc, const char **argv) { +#if defined(STM32L0) || defined(STM32F3) || defined(STM32F4) + extern char serial_no[13]; +#else extern char serial_no[9]; - traceswo_init(); +#endif + uint32_t baudrate = 0; + (void)t; + + if (argc > 1) + baudrate = atoi(argv[1]); + + traceswo_init(baudrate); gdb_outf("%s:%02X:%02X\n", serial_no, 5, 0x85); return true; } diff --git a/src/platforms/common/traceswo.h b/src/platforms/common/traceswo.h index 5566f944..fb57a892 100644 --- a/src/platforms/common/traceswo.h +++ b/src/platforms/common/traceswo.h @@ -22,7 +22,7 @@ #include -void traceswo_init(void); +void traceswo_init(uint32_t baudrate); void trace_buf_drain(usbd_device *dev, uint8_t ep); #endif From fc25a3339aeb511153a787863c71363b6e953e94 Mon Sep 17 00:00:00 2001 From: Uwe Bonnes Date: Thu, 26 Oct 2017 15:13:03 +0200 Subject: [PATCH 4/6] traceswoasync: Implement async swo for stm32. Use for stlink. Uses dma with large buffer. Pull up swo to provide idle level on unconnected swo pin. --- src/platforms/stlink/Makefile.inc | 1 + src/platforms/stlink/platform.h | 20 ++++- src/platforms/stm32/traceswoasync.c | 133 ++++++++++++++++++++++++++++ 3 files changed, 152 insertions(+), 2 deletions(-) create mode 100644 src/platforms/stm32/traceswoasync.c diff --git a/src/platforms/stlink/Makefile.inc b/src/platforms/stlink/Makefile.inc index 18486e83..4bde36c6 100644 --- a/src/platforms/stlink/Makefile.inc +++ b/src/platforms/stlink/Makefile.inc @@ -26,6 +26,7 @@ SRC += cdcacm.c \ serialno.c \ timing.c \ timing_stm32.c \ + traceswoasync.c \ stlink_common.c \ all: blackmagic.bin blackmagic_dfu.bin blackmagic_dfu.hex dfu_upgrade.bin dfu_upgrade.hex diff --git a/src/platforms/stlink/platform.h b/src/platforms/stlink/platform.h index 5cb29ccc..83eb90a3 100644 --- a/src/platforms/stlink/platform.h +++ b/src/platforms/stlink/platform.h @@ -68,6 +68,9 @@ #define LED_PORT_UART GPIOC #define LED_UART GPIO14 +#define PLATFORM_HAS_TRACESWO 1 +#define NUM_TRACE_PACKETS (192) /* This is an 12K buffer */ + #define TMS_SET_MODE() \ gpio_set_mode(TMS_PORT, GPIO_MODE_OUTPUT_50_MHZ, \ GPIO_CNF_OUTPUT_PUSHPULL, TMS_PIN); @@ -87,13 +90,12 @@ #define USB_ISR usb_lp_can_rx0_isr /* Interrupt priorities. Low numbers are high priority. * For now USART2 preempts USB which may spin while buffer is drained. - * TIM3 is used for traceswo capture and must be highest priority. */ #define IRQ_PRI_USB (2 << 4) #define IRQ_PRI_USBUSART (1 << 4) #define IRQ_PRI_USBUSART_TIM (3 << 4) #define IRQ_PRI_USB_VBUS (14 << 4) -#define IRQ_PRI_TIM3 (0 << 4) +#define IRQ_PRI_SWO_DMA (1 << 4) #define USBUSART USART2 #define USBUSART_CR1 USART2_CR1 @@ -115,6 +117,20 @@ int usbuart_debug_write(const char *buf, size_t len); # define DEBUG(...) #endif +/* On F103, only USART1 is on AHB2 and can reach 4.5 MBaud at 72 MHz.*/ +#define SWO_UART USART1 +#define SWO_UART_DR USART1_DR +#define SWO_UART_CLK RCC_USART1 +#define SWO_UART_PORT GPIOA +#define SWO_UART_RX_PIN GPIO10 + +/* This DMA channel is set by the USART in use */ +#define SWO_DMA_BUS DMA1 +#define SWO_DMA_CLK RCC_DMA1 +#define SWO_DMA_CHAN DMA_CHANNEL5 +#define SWO_DMA_IRQ NVIC_DMA1_CHANNEL5_IRQ +#define SWO_DMA_ISR(x) dma1_channel5_isr(x) + extern uint16_t led_idle_run; #define LED_IDLE_RUN led_idle_run #define SET_RUN_STATE(state) {running_status = (state);} diff --git a/src/platforms/stm32/traceswoasync.c b/src/platforms/stm32/traceswoasync.c new file mode 100644 index 00000000..dfa6baee --- /dev/null +++ b/src/platforms/stm32/traceswoasync.c @@ -0,0 +1,133 @@ +/* + * This file is part of the Black Magic Debug project. + * + * Based on work that is Copyright (C) 2017 Black Sphere Technologies Ltd. + * Copyright (C) 2017 Dave Marples + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* This file implements capture of the TRACESWO output using ASYNC signalling. + * + * ARM DDI 0403D - ARMv7M Architecture Reference Manual + * ARM DDI 0337I - Cortex-M3 Technical Reference Manual + * ARM DDI 0314H - CoreSight Components Technical Reference Manual + */ + +/* TDO/TRACESWO signal comes into the SWOUSART RX pin. + */ + +#include "general.h" +#include "cdcacm.h" +#include "platform.h" + +#include +#include +#include +#include +#include +#include + +/* For speed this is set to the USB transfer size */ +#define FULL_SWO_PACKET (64) +/* Default line rate....used as default for a request without baudrate */ +#define DEFAULTSPEED (2250000) + +static volatile uint32_t w; /* Packet currently received via UART */ +static volatile uint32_t r; /* Packet currently waiting to transmit to USB */ +/* Packets arrived from the SWO interface */ +static uint8_t trace_rx_buf[NUM_TRACE_PACKETS * FULL_SWO_PACKET]; +/* Packet pingpong buffer used for receiving packets */ +static uint8_t pingpong_buf[2 * FULL_SWO_PACKET]; + +void trace_buf_drain(usbd_device *dev, uint8_t ep) +{ + static volatile char inBufDrain; + + /* If we are already in this routine then we don't need to come in again */ + if (__atomic_test_and_set (&inBufDrain, __ATOMIC_RELAXED)) + return; + /* Attempt to write everything we buffered */ + if ((w != r) && (usbd_ep_write_packet(dev, ep, + &trace_rx_buf[r * FULL_SWO_PACKET], + FULL_SWO_PACKET))) + r =(r + 1) % NUM_TRACE_PACKETS; + __atomic_clear (&inBufDrain, __ATOMIC_RELAXED); +} + +void traceswo_setspeed(uint32_t baudrate) +{ + dma_disable_channel(SWO_DMA_BUS, SWO_DMA_CHAN); + usart_disable(SWO_UART); + usart_set_baudrate(SWO_UART, baudrate); + usart_set_databits(SWO_UART, 8); + usart_set_stopbits(SWO_UART, USART_STOPBITS_1); + usart_set_mode(SWO_UART, USART_MODE_RX); + usart_set_parity(SWO_UART, USART_PARITY_NONE); + usart_set_flow_control(SWO_UART, USART_FLOWCONTROL_NONE); + + /* Set up DMA channel*/ + dma_channel_reset(SWO_DMA_BUS, SWO_DMA_CHAN); + dma_set_peripheral_address(SWO_DMA_BUS, SWO_DMA_CHAN, + (uint32_t)&SWO_UART_DR); + dma_set_read_from_peripheral(SWO_DMA_BUS, SWO_DMA_CHAN); + dma_enable_memory_increment_mode(SWO_DMA_BUS, SWO_DMA_CHAN); + dma_set_peripheral_size(SWO_DMA_BUS, SWO_DMA_CHAN, DMA_CCR_PSIZE_8BIT); + dma_set_memory_size(SWO_DMA_BUS, SWO_DMA_CHAN, DMA_CCR_MSIZE_8BIT); + dma_set_priority(SWO_DMA_BUS, SWO_DMA_CHAN, DMA_CCR_PL_HIGH); + dma_enable_transfer_complete_interrupt(SWO_DMA_BUS, SWO_DMA_CHAN); + dma_enable_half_transfer_interrupt(SWO_DMA_BUS, SWO_DMA_CHAN); + dma_enable_circular_mode(SWO_DMA_BUS,SWO_DMA_CHAN); + + usart_enable(SWO_UART); + nvic_enable_irq(SWO_DMA_IRQ); + w = r = 0; + dma_set_memory_address(SWO_DMA_BUS, SWO_DMA_CHAN, (uint32_t)pingpong_buf); + dma_set_number_of_data(SWO_DMA_BUS, SWO_DMA_CHAN, 2 * FULL_SWO_PACKET); + dma_enable_channel(SWO_DMA_BUS, SWO_DMA_CHAN); + usart_enable_rx_dma(SWO_UART); +} + +void SWO_DMA_ISR(void) +{ + if (DMA_ISR(SWO_DMA_BUS) & DMA_ISR_HTIF(SWO_DMA_CHAN)) { + DMA_IFCR(SWO_DMA_BUS) |= DMA_ISR_HTIF(SWO_DMA_CHAN); + memcpy(&trace_rx_buf[w * FULL_SWO_PACKET], pingpong_buf, + FULL_SWO_PACKET); + } + if (DMA_ISR(SWO_DMA_BUS) & DMA_ISR_TCIF(SWO_DMA_CHAN)) { + DMA_IFCR(SWO_DMA_BUS) |= DMA_ISR_TCIF(SWO_DMA_CHAN); + memcpy(&trace_rx_buf[w * FULL_SWO_PACKET], + &pingpong_buf[FULL_SWO_PACKET], FULL_SWO_PACKET); + } + w = (w + 1) % NUM_TRACE_PACKETS; + trace_buf_drain(usbdev, 0x85); +} + +void traceswo_init(uint32_t baudrate) +{ + if (!baudrate) + baudrate = DEFAULTSPEED; + + rcc_periph_clock_enable(SWO_UART_CLK); + rcc_periph_clock_enable(SWO_DMA_CLK); + + gpio_set_mode(SWO_UART_PORT, GPIO_MODE_INPUT, + GPIO_CNF_INPUT_PULL_UPDOWN, SWO_UART_RX_PIN); + /* Pull SWO pin high to keep open SWO line ind uart idle state!*/ + gpio_set(SWO_UART_PORT, SWO_UART_RX_PIN); + nvic_set_priority(SWO_DMA_IRQ, IRQ_PRI_SWO_DMA); + nvic_enable_irq(SWO_DMA_IRQ); + traceswo_setspeed(baudrate); +} From 29cdba0d70d5a4e0453c451981a104668a427abd Mon Sep 17 00:00:00 2001 From: Uwe Bonnes Date: Fri, 27 Oct 2017 16:15:46 +0200 Subject: [PATCH 5/6] SWO: Some explanations and a test program. --- UsingSWO | 254 +++++++++++++++++++++ scripts/swolisten.c | 544 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 798 insertions(+) create mode 100644 UsingSWO create mode 100644 scripts/swolisten.c diff --git a/UsingSWO b/UsingSWO new file mode 100644 index 00000000..e582df53 --- /dev/null +++ b/UsingSWO @@ -0,0 +1,254 @@ +SWO is a datastream that comes out of a single pin when the debug interface +is in SWD mode. It can be encoded either using NRZ (UART) or RZ (Manchester) +formats. The pin is a dedicated one that would be used for TDO when the +debug interface is in JTAG mode. On the STM32 it's port PB3. + +When in NRZ mode the SWO data rate that comes out of the chip _must_ match +the rate that the debugger expects. By default on BMP the baudrate is +2.25MBps but that can be changed as an optional parameter to the monitor +traceswo command, like this; + +monitor traceswo 115200 + +....would set the swo output at the low speed of 115kbps. + +We are constrained on maximum input speed by both the capabilities of the +BMP STM32F103 USART and the ability to get the packets back out over the USB +link. The UART baudrate is set by b=(72x10^6)/(16*d)...so for d=1 that means +a maximum speed of 4.5Mbps. For continious streaming that turns out to be +_too_ fast for the USB link, so the next available option is the 2.25Mbps +that we use. ....you can safely use the 4.5Mbps setting if your debug data +is bursty, or if you're using a different CPU to the STM32F103 as your BMP +host, but you potentially run the risk of losing packets if you have long +runs of sending which the usb cannot flush in time (there's a 12K buffer, so +the it is a pretty long run before it becomes a problem). + +Note that the baudrate equation means there are only certain speeds +available. The highest half dozen are; + +1 4.50 Mbps +2 2.25 Mbps +3 1.50 Mbps +4 1.125 Mbps +5 0.900 Mbps +6 0.750 Mbps + +...the USART will cope with some timing slip, but it's advisible to stay as +close to these values as you can. As the speed comes down the spread between +each valid value so mis-timing is less of an issue. The 'monitor traceswo +' command will automatically find the closest divisor to the value you +set for the speed, so be aware the error could be significant. + +Depending on what you're using to wake up SWO on the target side, you may +need code to get it into the correct mode and emitting data. You can do that +via gdb direct memory accesses, or from program code. + +An example for a STM32F103 for the UART (NRZ) data format that we use; + + /* STM32 specific configuration to enable the TRACESWO IO pin */ + RCC->APB2ENR |= RCC_APB2ENR_AFIOEN; + AFIO->MAPR |= (2 << 24); // Disable JTAG to release TRACESWO + DBGMCU->CR |= DBGMCU_CR_TRACE_IOEN; // Enable IO trace pins + + *((volatile unsigned *)(0xE0040010)) = 31; // Output bits at 72000000/(31+1)=2.25MHz. + *((volatile unsigned *)(0xE00400F0)) = 2; // Use Async mode (1 for RZ/Manchester) + *((volatile unsigned *)(0xE0040304)) = 0; // Disable formatter + + /* Configure instrumentation trace macroblock */ + ITM->LAR = 0xC5ACCE55; + ITM->TCR = 0x00010005; + ITM->TER = 0xFFFFFFFF; // Enable all stimulus ports + +Code for the STM32L476 might look like: +#define BAUDRATE 115200 + DBGMCU->CR |= DBGMCU_CR_TRACE_IOEN; /* Enable IO pins for Async trace */ + uint32_t divisor, clk_frequency; + clk_frequency = NutGetCpuClock(); + divisor = clk_frequency / BAUDRATE; + divisor--; + TPI->CSPSR = 1; /* port size = 1 bit */ + TPI->ACPR = divisor; + TPI->SPPR = 2; /*Use Async mode pin protocol */ + TPI->FFCR = 0x00; /* Bypass the TPIU formatter and send output directly*/ + +/* Configure Trace Port Interface Unit */ + CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk; // Enable access to registers + DWT->CTRL = 0x400003FE; // DWT needs to provide sync for ITM + ITM->LAR = 0xC5ACCE55; // Allow access to the Control Register + ITM->TPR = 0x0000000F; // Trace access privilege from user level code, please + ITM->TCR = 0x0001000D; // ITM_TCR_TraceBusID_Msk | ITM_TCR_DWTENA_Msk | ITM_TCR_SYNCENA_Msk | ITM_TCR_ITMENA_Msk + ITM->TER = 1; // Only Enable stimulus port 1 + + while(1) { + for (uint32_t i = 'A'; i <= 'Z'; i++) { + ITM_SendChar(i); + NutSleep(1); + } + } + +If you're using RZ mode (e.g. on a genuine BMP) then you will need the trace +output speed to be quite a lot lower...in the order of 200kHz by means of +changing the divisor to something like 359. That's because the STM32F103 +doesn't have a dedicated RZ decoder so it all has to be done in +software. The advantage of RZ is that the probe can adapt to the speed of +the target, so you don't have to set the speed on the probe in the monitor +traceswo command, and it will be tolerant of different speeds. + +The SWO data appears on USB Interface 5, Endpoint 5. + +SWOListen +========= +A program swolisten.c is found in ./scripts which will listen to this +endpoint, decode the datastream, and output it to a set of unix fifos which +can then be used as the input to other programs (e.g. cat, or something more +sophisticated like gnuplot, octave or whatever). This program doesn't care +if the data originates from a RZ or NRZ port, or at what speed. + +Note that swolisten can be used with either BMP firmware, or with a +conventional TTL serial dongle. See at the bottom of this file for +information on how to use a dongle. + +The command line to build the swolisten tool is; + +gcc -I /usr/local/include/libusb-1.0 -L /usr/local/lib -lusb-1.0 swolisten.c -o swolisten + +For Opensuse: +gcc -I /usr/include/libusb-1.0 -lusb-1.0 swolisten.c swolisten -std=gnu99 -g -Og + +...you will obviously need to change the paths to your libusb files. + +Attach to BMP to your PC: +Start gdb: "arm-none-eabi-gdb" +Choose bmp as target, like: + "target extended /dev/ttyACM0(*)" +Start SWO output: "mon traceswo" +If async SWO is used, give the baudrate your device sends +out as argument. 2.25 MBaud is the default, for the STM32L476 example above +the command would be: "mon traceswo 115200(*)". +Scan the SWD "mon swdp_scan" +Attach to the device: : "attach 1" +Start the program: "r". +(*) Your milage may vary +Now start swolisten without further options. + +By default the tool will create fifos for the first 32 channels in a +directory swo (which you will need to create) as follows; + +>ls swo/ +chan00 chan02 chan04 chan06 chan08 chan0A chan0C chan0E chan10 chan12 chan14 +chan16 chan18 chan1A chan1C chan1E chan01 chan03 chan05 chan07 chan09 chan0B +chan0D chan0F chan11 chan13 chan15 chan17 chan19 chan1B chan1D chan1F + +>cat swo/channel0 +<> + +With the F103 and L476 examples above, an endless stream of +"ABCDEFGHIJKLMNOPQRSTUVWXYZ" should be seen. During reset of the target +device, no output will appear, but with release of reset output restarts. + +Information about command line options can be found with the -h option. +swolisten is specifically designed to be 'hardy' to probe and target +disconnects and restarts (y'know, like you get in the real world). The +intention being to give you streams whenever it can get them. It does _not_ +require gdb to be running. For the time being traceswo is not turned on by +default in the BMP to avoid possible interactions and making the overall +thing less reliable so You do need gdb to send the initial 'monitor +traceswo' to the probe, but beyond that there's no requirement for gdb to be +present. + +Reliability +=========== + +A whole chunk of work has gone into making sure the dataflow over the SWO +link is reliable. The TL;DR is that the link _is_ reliable. There are +factors outside of our control (i.e. the USB bus you connect to) that could +potentially break the reliabilty but there's not too much we can do about +that since the SWO link is unidirectional (no opportunity for +re-transmits). The following section provides evidence for the claim that +the link is good; + +A test 'mule' sends data flat out to the link at the maximum data rate of +2.25Mbps using a loop like the one below; + +while (1) +{ + for (uint32_t r=0; r<26; r++) + { + for (uint32_t g=0; g<31; g++) + { + ITM_SendChar('A'+r); + } + ITM_SendChar('\n'); + } +} + +100MB of data (more than 200MB of actual SWO packets, due to the encoding) was sent from the mule to the BMP where the +output from swolisten chan00 was cat'ted into a file; + +>cat swo/chan00 > o + +....this process was interrupted once the file had grown to 100MB. The first +and last lines were removed from it (these represent previously buffered +data and an incomplete packet at the point where the capture was +interrupted) and the resulting file analysed for consistency; + +> sort o | uniq -c + +The output was; + +126462 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +126462 BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB +126462 CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC +126462 DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD +126461 EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE +126461 FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +126461 GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG +126461 HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH +126461 IIIIIIIIIIIIIIIIIIIIIIIIIIIIIII +126461 JJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJ +126461 KKKKKKKKKKKKKKKKKKKKKKKKKKKKKKK +126461 LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL +126461 MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM +126461 NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN +126461 OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO +126461 PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP +126461 QQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQ +126461 RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR +126461 SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS +126461 TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT +126461 UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU +126461 VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV +126461 WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW +126461 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +126461 YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY +126461 ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ + +(On inspection, the last line of recorded data was indeed a 'D' line). + +Swolisten, using a TTL Serial Dongle +==================================== + +The NRZ data that comes out of the SWO is just UART formatted, but in a +frame. swolisten has been extended to accomodate TTL Serial Dongles that +can pick this up. Success has been had with CP2102 dongles at up to 921600 +baud. + +To use this mode just connect SWO to the RX pin of your dongle, and start +swolisten with parmeters representing the speed and port. An example; + +>./swolisten -p /dev/cu.SLAB_USBtoUART -v -b swo/ -s 921600 + +Any individual dongle will only support certain baudrates (Generally +multiples of 115200) so you may have to experiment to find the best +supported ones. For the CP2102 dongle 1.3824Mbps wasn't supported and +1.8432Mbps returned corrupted data. + +Please email dave@marples.net with information about dongles you find work +well and at what speed. + +Further information +=================== +SWO is a wide field. Read e.g. the blogs around SWD on +http://shadetail.com/blog/swo-starting-the-steroids/ +An open source program suite for SWO under active development is +https://github.com/mubes/orbuculum \ No newline at end of file diff --git a/scripts/swolisten.c b/scripts/swolisten.c new file mode 100644 index 00000000..1ce141aa --- /dev/null +++ b/scripts/swolisten.c @@ -0,0 +1,544 @@ +/* + * SWO Splitter for Blackmagic Probe and others. + * ============================================= + * + * This file is part of the Black Magic Debug project. + * + * Copyright (C) 2017 Dave Marples + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define VID (0x1d50) +#define PID (0x6018) +#define INTERFACE (5) +#define ENDPOINT (0x85) + +#define TRANSFER_SIZE (64) +#define NUM_FIFOS 32 +#define MAX_FIFOS 128 + +#define CHANNELNAME "chan" + +#define BOOL char +#define FALSE (0) +#define TRUE (!FALSE) + +// Record for options, either defaults or from command line +struct +{ + BOOL verbose; + BOOL dump; + int nChannels; + char *chanPath; + char *port; + int speed; +} options = {.nChannels=NUM_FIFOS, .chanPath="", .speed=115200}; + +// Runtime state +struct +{ + int fifo[MAX_FIFOS]; +} _r; + +// ==================================================================================================== +// ==================================================================================================== +// ==================================================================================================== +// Internals +// ==================================================================================================== +// ==================================================================================================== +// ==================================================================================================== +static BOOL _runFifo(int portNo, int listenHandle, char *fifoName) + +{ + int pid,fifo; + int readDataLen, writeDataLen; + + if (mkfifo(fifoName,0666)<0) + { + return FALSE; + } + + pid=fork(); + + if (pid==0) + { + char rxdata[TRANSFER_SIZE]; + int fifo; + + /* Don't kill this sub-process when any reader or writer evaporates */ + signal(SIGPIPE, SIG_IGN); + + while (1) + { + /* This is the child */ + fifo=open(fifoName,O_WRONLY); + + while (1) + { + readDataLen=read(listenHandle,rxdata,TRANSFER_SIZE); + if (readDataLen<=0) + { + exit(0); + } + + writeDataLen=write(fifo,rxdata,readDataLen); + if (writeDataLen<=0) + { + break; + } + } + close(fifo); + } + } + else if (pid<0) + { + /* The fork failed */ + return FALSE; + } + return TRUE; +} +// ==================================================================================================== +static BOOL _makeFifoTasks(void) + +/* Create each sub-process that will handle a port */ + +{ + char fifoName[PATH_MAX]; + + int f[2]; + + for (int t=0; t0) + { + close(_r.fifo[t]); + sprintf(fifoName,"%s%s%02X",options.chanPath,CHANNELNAME,t); + unlink(fifoName); + remainingProcesses++; + } + } + + while (remainingProcesses--) + { + waitpid(-1,&statloc,0); + } +} +// ==================================================================================================== +// ==================================================================================================== +// ==================================================================================================== +// Handlers for each message type +// ==================================================================================================== +// ==================================================================================================== +// ==================================================================================================== +void _handleSWIT(uint8_t addr, uint8_t length, uint8_t *d) + +{ + if (addr ",*c,_protoNames[p]); +#endif + + switch (p) + { + // ----------------------------------------------------- + case ITM_IDLE: + if (*c==0b01110000) + { + /* This is an overflow packet */ + if (options.verbose) + fprintf(stderr,"Overflow!\n"); + break; + } + // ********** + if (*c==0) + { + /* This is a sync packet - expect to see 4 more 0's followed by 0x80 */ + targetCount=4; + currentCount=0; + p=ITM_SYNCING; + break; + } + // ********** + if (!(*c&0x0F)) + { + currentCount=1; + /* This is a timestamp packet */ + rxPacket[0]=*c; + + if (!(*c&0x80)) + { + /* A one byte output */ + _handleTS(currentCount,rxPacket); + } + else + { + p=ITM_TS; + } + break; + } + // ********** + if ((*c&0x0F) == 0x04) + { + /* This is a reserved packet */ + break; + } + // ********** + if (!(*c&0x04)) + { + /* This is a SWIT packet */ + if ((targetCount=*c&0x03)==3) + targetCount=4; + srcAddr=(*c&0xF8)>>3; + currentCount=0; + p=ITM_SWIT; + break; + } + // ********** + if (options.verbose) + fprintf(stderr,"Illegal packet start in IDLE state\n"); + break; + // ----------------------------------------------------- + case ITM_SWIT: + rxPacket[currentCount]=*c; + currentCount++; + + if (currentCount>=targetCount) + { + p=ITM_IDLE; + _handleSWIT(srcAddr, targetCount, rxPacket); + } + break; + // ----------------------------------------------------- + case ITM_TS: + rxPacket[currentCount++]=*c; + if (!(*c&0x80)) + { + /* We are done */ + _handleTS(currentCount,rxPacket); + } + else + { + if (currentCount>4) + { + /* Something went badly wrong */ + p=ITM_IDLE; + } + break; + } + + // ----------------------------------------------------- + case ITM_SYNCING: + if ((*c==0) && (currentCount

\n",progName); + printf(" b: for channels\n"); + printf(" h: This help\n"); + printf(" d: Dump received data without further processing\n"); + printf(" n: of channels to populate\n"); + printf(" p: to use\n"); + printf(" s: to use\n"); + printf(" v: Verbose mode\n"); +} +// ==================================================================================================== +int _processOptions(int argc, char *argv[]) + +{ + int c; + while ((c = getopt (argc, argv, "vdn:b:hp:s:")) != -1) + switch (c) + { + case 'v': + options.verbose = 1; + break; + case 'd': + options.dump = 1; + break; + case 'p': + options.port=optarg; + break; + case 's': + options.speed=atoi(optarg); + break; + case 'h': + _printHelp(argv[0]); + return FALSE; + case 'n': + options.nChannels=atoi(optarg); + if ((options.nChannels<1) || (options.nChannels>MAX_FIFOS)) + { + fprintf(stderr,"Number of channels out of range (1..%d)\n",MAX_FIFOS); + return FALSE; + } + break; + case 'b': + options.chanPath = optarg; + break; + case '?': + if (optopt == 'b') + fprintf (stderr, "Option '%c' requires an argument.\n", optopt); + else if (!isprint (optopt)) + fprintf (stderr,"Unknown option character `\\x%x'.\n", optopt); + return FALSE; + default: + return FALSE; + } + + if (options.verbose) + { + fprintf(stdout,"Verbose: TRUE\nBasePath: %s\n",options.chanPath); + if (options.port) + { + fprintf(stdout,"Serial Port: %s\nSerial Speed: %d\n",options.port,options.speed); + } + } + return TRUE; +} +// ==================================================================================================== +int usbFeeder(void) + +{ + + unsigned char cbw[TRANSFER_SIZE]; + libusb_device_handle *handle; + libusb_device *dev; + int size; + + while (1) + { + if (libusb_init(NULL) < 0) + { + fprintf(stderr,"Failed to initalise USB interface\n"); + return (-1); + } + + while (!(handle = libusb_open_device_with_vid_pid(NULL, VID, PID))) + { + usleep(500000); + } + + if (!(dev = libusb_get_device(handle))) + continue; + + if (libusb_claim_interface (handle, INTERFACE)<0) + continue; + + while (0==libusb_bulk_transfer(handle, ENDPOINT, cbw, TRANSFER_SIZE, &size, 10)) + { + unsigned char *c=cbw; + if (options.dump) + printf(cbw); + else + while (size--) + _protocolPump(c++); + } + + libusb_close(handle); + } +} +// ==================================================================================================== +int serialFeeder(void) + +{ + int f; + unsigned char cbw[TRANSFER_SIZE]; + ssize_t t; + struct termios settings; + + while (1) + { + while ((f=open(options.port,O_RDONLY))<0) + { + if (options.verbose) + { + fprintf(stderr,"Can't open serial port\n"); + } + usleep(500000); + } + + if (options.verbose) + { + fprintf(stderr,"Port opened\n"); + } + + if (tcgetattr(f, &settings) <0) + { + perror("tcgetattr"); + return(-3); + } + + if (cfsetspeed(&settings, options.speed)<0) + { + perror("Setting input speed"); + return -3; + } + settings.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); + settings.c_cflag &= ~PARENB; /* no parity */ + settings.c_cflag &= ~CSTOPB; /* 1 stop bit */ + settings.c_cflag &= ~CSIZE; + settings.c_cflag |= CS8 | CLOCAL; /* 8 bits */ + settings.c_oflag &= ~OPOST; /* raw output */ + + if (tcsetattr(f, TCSANOW, &settings)<0) + { + fprintf(stderr,"Unsupported baudrate\n"); + exit(-3); + } + + tcflush(f, TCOFLUSH); + + while ((t=read(f,cbw,TRANSFER_SIZE))>0) + { + unsigned char *c=cbw; + while (t--) + _protocolPump(c++); + } + if (options.verbose) + { + fprintf(stderr,"Read failed\n"); + } + close(f); + } +} +// ==================================================================================================== +int main(int argc, char *argv[]) + +{ + if (!_processOptions(argc,argv)) + { + exit(-1); + } + + atexit(_removeFifoTasks); + /* This ensures the atexit gets called */ + signal(SIGINT, intHandler); + if (!_makeFifoTasks()) + { + fprintf(stderr,"Failed to make channel devices\n"); + exit(-1); + } + + /* Using the exit construct rather than return ensures the atexit gets called */ + if (!options.port) + exit(usbFeeder()); + else + exit(serialFeeder()); + fprintf(stderr,"Returned\n"); + exit(0); +} +// ==================================================================================================== From fa62403ee3dcbf3c554f49f37bbe7fb4fd02b789 Mon Sep 17 00:00:00 2001 From: Mike Walters Date: Mon, 2 Apr 2018 23:45:56 +0100 Subject: [PATCH 6/6] nrf51: Add nRF51802 device id. (#331) --- src/target/nrf51.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/target/nrf51.c b/src/target/nrf51.c index 985005d1..c8c00ea9 100644 --- a/src/target/nrf51.c +++ b/src/target/nrf51.c @@ -130,6 +130,7 @@ bool nrf51_probe(target *t) case 0x007A: /* nRF51422 (rev 3) CEAA C0 */ case 0x008F: /* nRF51822 (rev 3) QFAA H1 See https://devzone.nordicsemi.com/question/97769/can-someone-conform-the-config-id-code-for-the-nrf51822qfaah1/ */ case 0x00D1: /* nRF51822 (rev 3) QFAA H2 */ + case 0x0114: /* nRF51802 (rev ?) QFAA A1 */ t->driver = "Nordic nRF51"; target_add_ram(t, 0x20000000, 0x4000); nrf51_add_flash(t, 0x00000000, 0x40000, NRF51_PAGE_SIZE);