[app][mdebug] support for SWO transport back to host
This commit is contained in:
@@ -106,7 +106,7 @@ unsigned usb_recv(void *data, unsigned len) {
|
||||
#endif
|
||||
return rxactual;
|
||||
}
|
||||
|
||||
|
||||
static udc_device_t mdebug_device = {
|
||||
.vendor_id = 0x18d1,
|
||||
.product_id = 0xdb03,
|
||||
@@ -139,10 +139,14 @@ static void mdebug_init(const struct app_descriptor *app)
|
||||
}
|
||||
|
||||
void handle_rswd(void);
|
||||
void swo_init(udc_endpoint_t *ept);
|
||||
void swo_config(unsigned mhz);
|
||||
|
||||
static void mdebug_entry(const struct app_descriptor *app, void *args)
|
||||
{
|
||||
udc_start();
|
||||
swo_init(txept);
|
||||
swo_config(1000000);
|
||||
|
||||
for (;;) {
|
||||
if (!online) {
|
||||
|
||||
@@ -141,6 +141,10 @@ void process_txn(u32 txnid, u32 *rx, int rxc, u32 *tx) {
|
||||
tx[txc++] = RSWD_MSG(CMD_CLOCK_KHZ, 0, n);
|
||||
}
|
||||
continue;
|
||||
case CMD_SWO_CLOCK:
|
||||
n = swo_set_clock(n);
|
||||
printf("swo clock is now %d KHz\n", n);
|
||||
continue;
|
||||
case CMD_VERSION:
|
||||
host_version = n;
|
||||
tx[txc++] = RSWD_MSG(CMD_VERSION, 0, VERSION_1_0);
|
||||
|
||||
@@ -56,10 +56,12 @@
|
||||
#define CMD_TRACE 0x08 /* op=tracebits n=0 */
|
||||
#define CMD_BOOTLOADER 0x09 /* return to bootloader for reflashing */
|
||||
#define CMD_SET_CLOCK 0x0A /* set SWCLK rate to n khz */
|
||||
#define CMD_SWO_CLOCK 0x0B /* set SWOCLK rate to n khz, 0 = disable SWO */
|
||||
|
||||
/* valid: target to host */
|
||||
#define CMD_STATUS 0x10 /* op=errorcode, arg=commands since last TXN_START */
|
||||
#define CMD_SWD_DATA 0x11 /* op=0 arg=count, payload: data x count */
|
||||
#define CMD_SWO_DATA 0x12 /* op=0 arg=count, payload: count * 4 bytes */
|
||||
|
||||
/* valid: target to host async */
|
||||
#define CMD_DEBUG_PRINT 0x20 /* arg*4 bytes of ascii debug output */
|
||||
|
||||
@@ -4,7 +4,8 @@ MODULE := $(LOCAL_DIR)
|
||||
|
||||
MODULE_SRCS += \
|
||||
$(LOCAL_DIR)/mdebug.c \
|
||||
$(LOCAL_DIR)/rswd.c
|
||||
$(LOCAL_DIR)/rswd.c \
|
||||
$(LOCAL_DIR)/swo-uart1.c
|
||||
|
||||
#MODULE_SRCS += $(LOCAL_DIR)/swd-sgpio.c
|
||||
MODULE_SRCS += $(LOCAL_DIR)/swd-m0sub.c
|
||||
|
||||
@@ -53,6 +53,8 @@ static void gpio_init(void) {
|
||||
pin_config(PIN_SWDIO, PIN_MODE(6) | PIN_PLAIN | PIN_INPUT | PIN_FAST);
|
||||
pin_config(PIN_SWCLK, PIN_MODE(6) | PIN_PLAIN | PIN_FAST);
|
||||
|
||||
pin_config(PIN_SWO, PIN_MODE(1) | PIN_PLAIN | PIN_INPUT | PIN_FAST);
|
||||
|
||||
gpio_set(GPIO_LED, 0);
|
||||
gpio_set(GPIO_RESET, 1);
|
||||
gpio_set(GPIO_RESET_TXEN, 0);
|
||||
|
||||
@@ -54,6 +54,7 @@ static void gpio_init(void) {
|
||||
pin_config(PIN_SWDIO_TXEN, PIN_MODE(0) | PIN_PLAIN);
|
||||
pin_config(PIN_SWDIO, PIN_MODE(0) | PIN_PLAIN | PIN_INPUT | PIN_FAST);
|
||||
pin_config(PIN_SWCLK, PIN_MODE(0) | PIN_PLAIN | PIN_FAST);
|
||||
pin_config(PIN_SWO, PIN_MODE(1) | PIN_PLAIN | PIN_INPUT | PIN_FAST);
|
||||
|
||||
gpio_set(GPIO_LED, 0);
|
||||
gpio_set(GPIO_RESET, 1);
|
||||
|
||||
@@ -24,6 +24,7 @@ int swd_write(unsigned reg, unsigned val);
|
||||
int swd_read(unsigned reg, unsigned *val);
|
||||
|
||||
unsigned swd_set_clock(unsigned khz);
|
||||
unsigned swo_set_clock(unsigned khz);
|
||||
void swd_hw_reset(int assert);
|
||||
|
||||
// swdp_read/write() register codes
|
||||
|
||||
147
app/mdebug/swo-uart1.c
Normal file
147
app/mdebug/swo-uart1.c
Normal file
@@ -0,0 +1,147 @@
|
||||
/* swo-uart1.c
|
||||
*
|
||||
* Copyright 2015 Brian Swetland <swetland@frotz.net>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <debug.h>
|
||||
#include <reg.h>
|
||||
#include <kernel/thread.h>
|
||||
|
||||
#include <dev/udc.h>
|
||||
#include <arch/arm/cm.h>
|
||||
|
||||
#include <platform/lpc43xx-uart.h>
|
||||
#include <platform/lpc43xx-gpdma.h>
|
||||
#include <platform/lpc43xx-clocks.h>
|
||||
|
||||
#include "rswdp.h"
|
||||
|
||||
#define UART_BASE UART1_BASE
|
||||
#define BASE_UART_CLK BASE_UART1_CLK
|
||||
|
||||
extern uint8_t __lpc43xx_main_clock_sel;
|
||||
extern uint32_t __lpc43xx_main_clock_mhz;
|
||||
|
||||
#define TXNSIZE 128
|
||||
#define TXNCOUNT 4
|
||||
|
||||
typedef struct swo_txn {
|
||||
unsigned buf[TXNSIZE/4 + 2];
|
||||
struct swo_txn *next;
|
||||
udc_request_t *req;
|
||||
unsigned busy;
|
||||
unsigned num;
|
||||
} txn_t;
|
||||
|
||||
static txn_t TXN[TXNCOUNT];
|
||||
static txn_t *txwr = TXN;
|
||||
static udc_endpoint_t *txept;
|
||||
|
||||
void swo_start_dma(void *ptr);
|
||||
|
||||
static void tx_done(udc_request_t *req, unsigned actual, int status) {
|
||||
txn_t *txn = req->context;
|
||||
txn->busy = 0;
|
||||
if (txwr == txn) {
|
||||
// writer wants to write here, and is waiting...
|
||||
swo_start_dma(txn->buf + 2);
|
||||
}
|
||||
}
|
||||
|
||||
void lpc43xx_DMA_IRQ(void) {
|
||||
txn_t *txn = txwr;
|
||||
arm_cm_irq_entry();
|
||||
writel(0xFF, DMA_INTTCCLR);
|
||||
writel(0xFF, DMA_INTERRCLR);
|
||||
if (udc_request_queue(txept, txn->req)) {
|
||||
// failed, usb probably offline, just re-use the buffer
|
||||
} else {
|
||||
txn->busy = 1;
|
||||
txwr = txn = txn->next;
|
||||
}
|
||||
if (!txn->busy) {
|
||||
// if busy, when the usb txn completes, it will start dma then
|
||||
swo_start_dma(txn->buf + 2);
|
||||
}
|
||||
arm_cm_irq_exit(0);
|
||||
}
|
||||
|
||||
void swo_init(udc_endpoint_t *_txept) {
|
||||
int n;
|
||||
txept = _txept;
|
||||
for (n = 0; n < TXNCOUNT; n++) {
|
||||
TXN[n].req = udc_request_alloc();
|
||||
TXN[n].req->context = TXN + n;
|
||||
TXN[n].req->buffer = TXN[n].buf;
|
||||
TXN[n].req->length = TXNSIZE + 8;
|
||||
TXN[n].req->complete = tx_done;
|
||||
TXN[n].num = n;
|
||||
TXN[n].busy = 0;
|
||||
TXN[n].next = TXN + (n + 1);
|
||||
TXN[n].buf[0] = RSWD_TXN_ASYNC;
|
||||
TXN[n].buf[1] = RSWD_MSG(CMD_SWO_DATA, 0, TXNSIZE / 4);
|
||||
}
|
||||
TXN[n-1].next = TXN;
|
||||
|
||||
// configure peripheral 4 as uart1_rx
|
||||
writel((readl(DMAMUX_REG) & DMAMUX_M(4)) | DMAMUX_P(4, P4_UART1_RX), DMAMUX_REG);
|
||||
writel(DMA_CONFIG_EN, DMA_CONFIG);
|
||||
NVIC_EnableIRQ(DMA_IRQn);
|
||||
|
||||
// kick off the process with an initial DMA
|
||||
swo_start_dma(txwr->buf + 2);
|
||||
}
|
||||
|
||||
void swo_start_dma(void *ptr) {
|
||||
writel(UART1_BASE + REG_RBR, DMA_SRC(0));
|
||||
writel((u32) ptr, DMA_DST(0));
|
||||
writel(0, DMA_LLI(0));
|
||||
writel(DMA_XFER_SIZE(TXNSIZE) |
|
||||
DMA_SRC_BURST(BURST_1) | DMA_DST_BURST(BURST_4) |
|
||||
DMA_SRC_BYTE | DMA_DST_WORD | DMA_SRC_MASTER1 | DMA_DST_MASTER0 |
|
||||
DMA_DST_INCR | DMA_PROT1 | DMA_TC_IE,
|
||||
DMA_CTL(0));
|
||||
writel(DMA_ENABLE | DMA_SRC_PERIPH(4) | DMA_FLOW_P2M_DMAc | DMA_TC_IRQ_EN,
|
||||
DMA_CFG(0));
|
||||
}
|
||||
void swo_config(unsigned mhz) {
|
||||
if (mhz > 0) {
|
||||
uint32_t div = __lpc43xx_main_clock_mhz / 16 / mhz;
|
||||
writel(BASE_CLK_SEL(__lpc43xx_main_clock_sel), BASE_UART_CLK);
|
||||
writel(LCR_DLAB, UART_BASE + REG_LCR);
|
||||
writel(div & 0xFF, UART_BASE + REG_DLL);
|
||||
writel((div >> 8) & 0xFF, UART_BASE + REG_DLM);
|
||||
writel(LCR_WLS_8 | LCR_SBS_1, UART_BASE + REG_LCR);
|
||||
writel(FCR_FIFOEN | FCR_RX_TRIG_1 | FCR_DMAMODE, UART_BASE + REG_FCR);
|
||||
}
|
||||
}
|
||||
|
||||
unsigned swo_set_clock(unsigned khz) {
|
||||
if (khz >= 6000) {
|
||||
khz = 6000;
|
||||
} else if (khz >= 4000) {
|
||||
khz = 4000;
|
||||
} else if (khz >= 3000) {
|
||||
khz = 3000;
|
||||
} else if (khz >= 2000) {
|
||||
khz = 2000;
|
||||
} else {
|
||||
khz = 1000;
|
||||
}
|
||||
swo_config(khz * 1000);
|
||||
return khz;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user