From b140014d11ca7ce89bda2732f41a2f3f5c1a923e Mon Sep 17 00:00:00 2001 From: Andy Spencer Date: Sun, 9 Mar 2014 00:26:06 +0000 Subject: [PATCH] Add dma and more tests --- common.mk | 4 +- hw2/main.cpp | 245 +++++++++++++++++++++++++++++++++++++++++++++-- hw2/makefile | 2 +- hw2/serial_dma.c | 162 +++++++++++++++++++++++++++++++ hw2/serial_dma.h | 50 ++++++++++ 5 files changed, 450 insertions(+), 13 deletions(-) create mode 100644 hw2/serial_dma.c create mode 100644 hw2/serial_dma.h diff --git a/common.mk b/common.mk index 374049e..6798650 100644 --- a/common.mk +++ b/common.mk @@ -6,8 +6,8 @@ GXX ?= arm-none-eabi-g++ GLD ?= arm-none-eabi-gcc OBJCOPY ?= arm-none-eabi-objcopy -CFLAGS ?= -Wall -Os -g --std=gnu99 -CXXFLAGS ?= -Wall -Os -g --std=gnu++98 +CFLAGS ?= -Wall -g --std=gnu99 +CXXFLAGS ?= -Wall -g --std=gnu++98 # Cross compiler flags CPPFLAGS += -I$(MBED) -I$(MBED)/TARGET_KL46Z diff --git a/hw2/main.cpp b/hw2/main.cpp index aac88f2..454bed5 100644 --- a/hw2/main.cpp +++ b/hw2/main.cpp @@ -1,4 +1,5 @@ #include "mbed.h" +#include "serial_dma.h" /** * Mode of operation: @@ -13,8 +14,58 @@ * 4. The offset is used to compensate the receivers local clock. * * Time synchronization is performed in both directions. + * + * + * Only port A, C, and D can do aysnc DMA (p. 67) + * + * Uart Sources: + * UART 0 UART 1 UART 2 + * xmt rcv xmt rcv xmt rcv + * --- --- --- --- --- --- + * A2 A1 **A19 A18** - - + * A14 A15 - - - - + * B17 B16 - - - - + * - - **C4 C3** - - + * D7 D6 - - **D3 D2** <<< + * - - - - **D5 D4** + * E20 E21 E0 E1 E16 E17 + * - - - - E22 E23 + * + * Pinout + * A1 B18 E30 C1 + * A2 B19 B20 C2 + * D3 C0 E23 B3 + * A12 C4 E22 B2 + * A4 C6 E21 B1 + * A5 C7 E20 B0 + * C8 C10 + * C9 C11 E2 P5-9V + * E3 GND + * A13 C13 E6 GND + * D2 C16 E16 P5V-USB + * D4 A7 E17 P3V3 + * D6 A6 E18 RST + * D7 A14 E19 P3V3 + * D5 A15 E31 SDA/D5 + * GND A15 + * VREFH A17 + * E0 B9 + * E1 -- */ +/* Trigger select options */ + +#define TMP_CONF_TRGSEL_EXTRG 0x0 // 0b0000 External trigger pin input (EXTRG_IN) +#define TMP_CONF_TRGSEL_CMP0 0x1 // 0b0001 CMP0 output +#define TMP_CONF_TRGSEL_PIT0 0x4 // 0b0100 PIT trigger 0 +#define TMP_CONF_TRGSEL_PIT1 0x5 // 0b0101 PIT trigger 1 +#define TMP_CONF_TRGSEL_TPM0 0x8 // 0b1000 TPM0 overflow +#define TMP_CONF_TRGSEL_TPM1 0x9 // 0b1001 TPM1 overflow +#define TMP_CONF_TRGSEL_TPM2 0xA // 0b1010 TPM2 overflow +#define TMP_CONF_TRGSEL_RTCA 0xC // 0b1100 RTC alarm +#define TMP_CONF_TRGSEL_RTCS 0xD // 0b1101 RTC seconds +#define TMP_CONF_TRGSEL_LPTMR 0xE // 0b1110 LPTMR trigger + /*********************** * Message Definitions * ***********************/ @@ -112,6 +163,13 @@ void serial_receive(void) { } +/*********************** + * Timestamp functions * + ***********************/ + +//void stamp() { +//} + /******************** * Data definitions * ********************/ @@ -123,24 +181,184 @@ DigitalOut led2(LED2); // UARTs tx rx Serial uart0(USBTX, USBRX); Serial uart1(PTE0, PTE1); -Serial uart2(PTE16, PTE17); +Serial uart2(PTD3, PTD2); + +// Serial DMA +sdma_t *sdma0; +sdma_t *sdma1; +sdma_t *sdma2; /******** * Main * ********/ +void test_tpm_init(void) +{ + // EXTRG_IN - PTB8 - alt 3 + // PTC0 - alt 3 + // PTC6 - alt 3 + + // Setup System Integration Module + SIM_Type *sim = SIM; + + sim->SCGC5 |= SIM_SCGC5_PORTA_MASK + | SIM_SCGC5_PORTB_MASK + | SIM_SCGC5_PORTC_MASK + | SIM_SCGC5_PORTD_MASK + | SIM_SCGC5_PORTE_MASK + | SIM_SCGC5_LPTMR_MASK; + + sim->SCGC6 |= SIM_SCGC6_TPM0_MASK + | SIM_SCGC6_TPM1_MASK + | SIM_SCGC6_TPM2_MASK + | SIM_SCGC6_DAC0_MASK + | SIM_SCGC6_ADC0_MASK + | SIM_SCGC6_PIT_MASK + | SIM_SCGC6_DMAMUX_MASK + | SIM_SCGC6_RTC_MASK; + + sim->SOPT2 |= SIM_SOPT2_TPMSRC(1); + + sim->SOPT4 = SIM_SOPT4_TPM1CLKSEL_MASK + | SIM_SOPT4_TPM1CH0SRC(3); + + printf("SOPT2:%08lx SCGC5:%08lx SCGC6:%08lx\r\n", + sim->SOPT2, sim->SCGC5, sim->SCGC6); + //SOPT2:05010000 SCGC5:00003f83 SCGC6:07800001 + + //sim->SOPT7 |= SIM_SOPT7_ADC0TRGSEL(TMP_CONF_TRGSEL_EXTRG); + + // Setup Port Control + PORT_Type *port = PORTC; + + PORTE->PCR[25] = PORT_PCR_ISF_MASK + | PORT_PCR_IRQC(0x1) + | PORT_PCR_MUX(3) ; + + port->PCR[0] = PORT_PCR_ISF_MASK + | PORT_PCR_IRQC(0x1) + | PORT_PCR_MUX(3) + | PORT_PCR_PE_MASK; + + // Setup Timer/PWM Module + volatile TPM_Type *tpm = TPM1; + + tpm->SC = TPM_SC_PS(0x7) + | TPM_SC_TOF_MASK; + + tpm->CNT = TPM_CNT_COUNT(0); + + tpm->MOD = TPM_CNT_COUNT(0xFFFF); + + tpm->CONTROLS[1].CnV = 0x1234; + tpm->CONTROLS[1].CnSC = TPM_CnSC_CHF_MASK + | TPM_CnSC_CHIE_MASK + | TPM_CnSC_ELSA_MASK; + + //tpm->CONTROLS[0].CnSC = TPM_CnSC_CHF_MASK + // | TPM_CnSC_CHIE_MASK + // | TPM_CnSC_MSB_MASK + // | TPM_CnSC_MSA_MASK + // | TPM_CnSC_ELSB_MASK + // | TPM_CnSC_ELSA_MASK; + + tpm->STATUS = TPM_STATUS_CH0F_MASK + | TPM_STATUS_CH1F_MASK + | TPM_STATUS_CH2F_MASK + | TPM_STATUS_CH3F_MASK + | TPM_STATUS_CH4F_MASK + | TPM_STATUS_CH5F_MASK + | TPM_STATUS_TOF_MASK; + + tpm->CONF = TPM_CONF_TRGSEL(TMP_CONF_TRGSEL_EXTRG) + | TPM_CONF_CSOO_MASK + | TPM_CONF_CSOT_MASK + | TPM_CONF_GTBEEN_MASK + | TPM_CONF_DBGMODE_MASK; + + tpm->SC = TPM_SC_CMOD(1) + | TPM_SC_PS(0x7) + | TPM_SC_TOF_MASK; + + printf("test - %02lx %08lx\r\n", tpm->CONTROLS[1].CnSC, tpm->CONTROLS[1].CnV); wait(0.1); +} + +void test_tpm_run(void) +{ + //static DigitalIn pin(PTC0); + //static DigitalIn pin(PTC2); + static int pin = 0; + + printf("%lx - PTC0:%08lx GPCR:%08lx:%08lx - SC:%04lx CNT:%04lx MOD:%04lx STATUS:%04lx CONF:%08lx - CnSC:%02lx CnV:%04lx\r\n", + (long)pin, PORTC->PCR[0], PORTC->GPCHR, PORTC->GPCLR, + TPM1->SC, TPM1->CNT, TPM1->MOD, TPM1->STATUS, TPM1->CONF, + TPM1->CONTROLS[1].CnSC, TPM1->CONTROLS[1].CnV); + TPM1->SC |= TPM_STATUS_TOF_MASK; + TPM1->STATUS |= TPM_STATUS_TOF_MASK; +} + +void test_pit_init(void) +{ + //printf("test_pit_init\r\n"); + + // Enable + SIM->SCGC6 |= SIM_SCGC6_PIT_MASK; + PIT->MCR = 0; + + // Channel 0 + PIT->CHANNEL[0].LDVAL = 0xFFFFFFFF; + PIT->CHANNEL[0].TCTRL = 0; + + // Channel 1 + PIT->CHANNEL[1].LDVAL = 0xFFFFFFFF; + PIT->CHANNEL[1].TCTRL = PIT_TCTRL_CHN_MASK; + + // Start timers + PIT->CHANNEL[0].TCTRL |= PIT_TCTRL_TEN_MASK; + PIT->CHANNEL[1].TCTRL |= PIT_TCTRL_TEN_MASK; + +} + +void test_pit_run(void) +{ + register volatile uint32_t *tmh asm("r4") = &PIT->LTMR64H; + register volatile uint32_t *tml asm("r5") = &PIT->LTMR64L; + + register uint32_t hi0 asm("r0"), lo0 asm("r1"); + register uint32_t hi1 asm("r2"), lo1 asm("r3"); + + asm("ldr %0, [%4]\n\t" // Two clocks per load + "ldr %1, [%5]\n\t" + "ldr %2, [%4]\n\t" + "ldr %3, [%5]\n\t" + : "=r"(hi0), "=r"(lo0), "=r"(hi1), "=r"(lo1) + : "r"(tmh), "r"(tml)); + + uint64_t tm0 = ~((uint64_t)hi0 << 32 | lo0); + uint64_t tm1 = ~((uint64_t)hi1 << 32 | lo1); + double bus = 24E6; // 24 MHz bus clock + + printf("tick %08lx:%08lx", (uint32_t)(tm0>>32), (uint32_t)tm0); + printf( " %08lx:%08lx", (uint32_t)(tm1>>32), (uint32_t)tm1); + printf( " %08lx", (uint32_t)(tm1-tm0)); + printf( " %f\r\n", (double)tm0 / bus); +} + void test_uart(void) { char xmt[32] = "hello, world"; char rcv[32] = {}; - printf("start\r\n"); - for (int i = 0; xmt[i]; i++) { - uart1.putc(xmt[i]); + sdma_write(sdma1, xmt, strlen(xmt)); + sdma_flush(sdma1); + + for (int i = 0; xmt[i]; i++) rcv[i] = uart2.getc(); - } - printf("xmt: %s\r\n", xmt); - printf("rcv: %s\r\n", rcv); + + printf("xmt: %s ", xmt); + printf("rcv: %s ", rcv); + printf("tag: dir:%08lx in:%08lx\r\n", + FPTD->PDDR, FPTD->PDIR); } void test_leds(void) @@ -155,11 +373,18 @@ int main(int argc, char **argv) uart1.baud(115200); uart2.baud(115200); + sdma1 = sdma_open(SDMA_UART1, SDMA_CHANNEL1); + sdma2 = sdma_open(SDMA_UART2, SDMA_CHANNEL2); + test_uart(); - test_leds(); + //test_leds(); + test_pit_init(); + //test_tpm_init(); while (1) { - printf("tick\r\n"); - test_leds(); + test_uart(); + //test_leds(); + //test_pit_run(); + //test_tpm_run(); } } diff --git a/hw2/makefile b/hw2/makefile index 00a0a47..1185448 100644 --- a/hw2/makefile +++ b/hw2/makefile @@ -1,5 +1,5 @@ PROG = mbed -OBJS = main.o +OBJS = main.o serial_dma.o CPPFLAGS = LDFLAGS = -lm diff --git a/hw2/serial_dma.c b/hw2/serial_dma.c new file mode 100644 index 0000000..c9ad643 --- /dev/null +++ b/hw2/serial_dma.c @@ -0,0 +1,162 @@ +#include + +#include +#include +#include +#include + +#include "serial_dma.h" + +/* Defines */ +#define SDMA_NUM 2 +#define SDMA_LEN 1024 + +/* Port structure */ +struct sdma_t { + /* DMA channel */ + struct { + uint32_t sar; // offset 0x00, Source Address Register + uint32_t dar; // offset 0x04, Destination Address Register + uint32_t dsr; // offset 0x08, DMA Status Register / Byte Count Register + uint32_t dcr; // offset 0x0C, DMA Control Register + } *dma; + + /* DMA mux */ + struct { + uint8_t cfg; // offset 0x00, Channel Configuration register + } *mux; + + /* Data buffering */ + int index; + int length[SDMA_NUM]; + uint8_t queue[SDMA_NUM][SDMA_LEN]; + + /* Error logging */ + int stuck; + int full; +}; + +/* DMA Request Sources */ +static int sdma_req_rx[] = { + [SDMA_UART0] 2, + [SDMA_UART1] 4, + [SDMA_UART2] 6, +}; +static int sdma_req_tx[] = { + [SDMA_UART0] 3, + [SDMA_UART1] 5, + [SDMA_UART2] 7, +}; + +/* Port data */ +static sdma_t sdma_ports[SDMA_NUM_UART]; + +/* DMA Functions */ +sdma_t *sdma_open(sdma_uart_t uart, sdma_dma_t dma) +{ + int rxreq = sdma_req_rx[uart]; (void)rxreq; + int txreq = sdma_req_tx[uart]; (void)txreq; + + // Setup port + sdma_t *port = &sdma_ports[uart]; + + port->dma = (void*)&DMA0->DMA[dma]; + port->mux = (void*)&DMAMUX0->CHCFG[dma]; + + // Enable DMA Cock + SIM->SCGC6 |= SIM_SCGC6_DMAMUX_MASK; + SIM->SCGC7 |= SIM_SCGC7_DMA_MASK; + + // Reset channel + port->dma->dsr = DMA_DSR_BCR_DONE_MASK; + + // Configure DMA transfer + port->dma->dar = (uint32_t)&UART1->D; + port->dma->dcr = DMA_DCR_CS_MASK | + DMA_DCR_SINC_MASK | + DMA_DCR_SSIZE(1) | + DMA_DCR_DSIZE(1) | + DMA_DCR_D_REQ_MASK; + + // Configure DMA Mux + port->mux->cfg = DMAMUX_CHCFG_SOURCE(txreq) | + DMAMUX_CHCFG_ENBL_MASK; + + // Configure UART for DMA Channel 0 + switch (uart) { + case SDMA_UART0: + UART0->C5 |= UART0_C5_TDMAE_MASK; + break; + + case SDMA_UART1: + UART1->C2 = UART_C2_TIE_MASK + | UART_C2_TE_MASK + | UART_C2_RE_MASK; + UART1->C4 = UART_C4_TDMAS_MASK; + break; + + case SDMA_UART2: + UART2->C2 = UART_C2_TIE_MASK + | UART_C2_TE_MASK + | UART_C2_RE_MASK; + UART2->C4 = UART_C4_TDMAS_MASK; + break; + } + return port; +} + +/* Write binary data out the DMA output queue */ +void sdma_write(sdma_t *port, void *data, int len) +{ + if (port->length[port->index] + len > SDMA_LEN) { + port->full++; + } else { + int pos = port->length[port->index]; + void *dst = &port->queue[port->index][pos]; + memcpy(dst, data, len); + port->length[port->index] += len; + } +} + +/* Write ASCII data to the output queue */ +void sdma_vprintf(sdma_t *port, const char *fmt, va_list ap) +{ + int pos = port->length[port->index]; + void *dst = &port->queue[port->index][pos]; + port->length[port->index] += + vsnprintf((char*)dst, SDMA_LEN-pos, fmt, ap); +} + +void sdma_printf(sdma_t *port, const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + sdma_vprintf(port, fmt, ap); + va_end(ap); +} + +/* Trigger DMA transmit of the current output queue + * and swap buffers so we can write into unused space */ +void sdma_flush(sdma_t *port) +{ + if (port->length[port->index] == 0) + return; + + // Wait for transmit complete + while (port->dma->dsr & DMA_DSR_BCR_BCR_MASK) + port->stuck++; + + // Reset channel + port->dma->dsr = DMA_DSR_BCR_DONE_MASK; + + // Set source address and length + port->dma->sar = (uint32_t)&port->queue[port->index]; + port->dma->dsr = DMA_DSR_BCR_BCR(port->length[port->index]); + + // Enable DMA transmit + port->dma->dcr |= DMA_DCR_ERQ_MASK; + + // Swap buffers + port->length[port->index] = 0; + port->index = (port->index + 1) % SDMA_NUM; +} diff --git a/hw2/serial_dma.h b/hw2/serial_dma.h new file mode 100644 index 0000000..db23146 --- /dev/null +++ b/hw2/serial_dma.h @@ -0,0 +1,50 @@ +#ifndef SERIAL_DMA_H +#define SERIAL_DMA_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Sizes */ +#define SDMA_NUM_UART 3 +#define SDMA_NUM_DMA 4 + +/* Serial Ports */ +typedef enum { + SDMA_UART0, + SDMA_UART1, + SDMA_UART2, +} sdma_uart_t; + +/* DMA Channels */ +typedef enum { + SDMA_CHANNEL0, + SDMA_CHANNEL1, + SDMA_CHANNEL2, + SDMA_CHANNEL3, +} sdma_dma_t; + +/* Port */ +typedef struct sdma_t sdma_t; + +/* Setup */ +sdma_t *sdma_open(sdma_uart_t uart, sdma_dma_t dma); + +/* Write */ +void sdma_write(sdma_t *port, void *data, int len); + +/* Print */ +void sdma_vprintf(sdma_t *port, const char *fmt, va_list ap); +void sdma_printf(sdma_t *port, const char *fmt, ...); + +/* Write */ +void sdma_flush(sdma_t *port); + +#ifdef __cplusplus +} +#endif + +#endif -- 2.43.2