From b1e665ed8d5ddd4f5596e06f38e612681ffbfadc Mon Sep 17 00:00:00 2001 From: jaseg Date: Tue, 17 Dec 2013 13:52:40 +0100 Subject: More robust error handling, USB-triggered frame latching --- firmware/main.c | 89 ++++++++++++++++++++++++++------------------------ firmware/startup_gcc.c | 3 +- 2 files changed, 47 insertions(+), 45 deletions(-) diff --git a/firmware/main.c b/firmware/main.c index 3c8e000..4419435 100644 --- a/firmware/main.c +++ b/firmware/main.c @@ -103,21 +103,6 @@ void SysTickIntHandler(void) { g_ulSysTickCount++; } -/* Will be called when a DMA transfer is complete */ -void SSI0IntHandler(void) { - /* FIXME is this necessary? */ - unsigned long ssistatus = SSIIntStatus(SSI0_BASE, 1); - MAP_SSIIntClear(SSI0_BASE, ssistatus); - - if(!MAP_uDMAChannelIsEnabled(11)){ - /* A TX DMA transfer was completed */ - /* FIXME actually, just set a flag here and kick off when all four controllers signal completion.*/ - /* Wait 1.2ms for the WS2801s to latch (the datasheet specifies at least 500µs) */ - MAP_SysCtlDelay(20000); - kickoff_transfers(); - } -} - unsigned long RxHandler(void *pvCBData, unsigned long ulEvent, unsigned long ulMsgValue, void *pvMsgData) { switch(ulEvent) { case USB_EVENT_CONNECTED: @@ -142,48 +127,68 @@ unsigned long RxHandler(void *pvCBData, unsigned long ulEvent, unsigned long ulM } typedef struct { + unsigned char command; /* 0x00 for frame data, 0x01 to initiate latch */ unsigned char crate_x; unsigned char crate_y; unsigned char rgb_data[CRATE_SIZE*BYTES_PER_PIXEL]; } FramebufferData; unsigned long framebuffer_read(void *data, unsigned long len) { - if(len != sizeof(FramebufferData)) - return len; + if(len < 1) + goto length_error; UARTprintf("Rearranging data.\n"); FramebufferData *fb = (FramebufferData *)data; + if(fb->command == 1){ + if(len != 1) + goto length_error; + UARTprintf("Starting DMA.\n"); + kickoff_transfers(); + }else{ + if(len != sizeof(FramebufferData)) + goto length_error; - unsigned int bus = fb->crate_x/CRATES_X; - fb->crate_x %= CRATES_X; + unsigned int bus = fb->crate_x/CRATES_X; + fb->crate_x %= CRATES_X; - if(bus > BUS_COUNT || fb->crate_y > CRATES_Y){ - UARTprintf("Invalid frame index\n"); - return len; - } + if(bus > BUS_COUNT || fb->crate_y > CRATES_Y){ + UARTprintf("Invalid frame index\n"); + return len; + } - /* Mirror crate map for the display's right half */ - if(bus >= BUS_COUNT/2) - fb->crate_x = CRATES_X - fb->crate_x - 1; - - unsigned int crate = CRATE_MAP[fb->crate_x + fb->crate_y*CRATES_X]; - for(unsigned int x=0; xrgb_data[src]; - framebuffer_input[dst + 1] = fb->rgb_data[src + 1]; - framebuffer_input[dst + 2] = fb->rgb_data[src + 2]; + /* Mirror crate map for the display's right half */ + if(bus >= BUS_COUNT/2) + fb->crate_x = CRATES_X - fb->crate_x - 1; + + unsigned int crate = CRATE_MAP[fb->crate_x + fb->crate_y*CRATES_X]; + for(unsigned int x=0; xrgb_data[src]; + framebuffer_input[dst + 1] = fb->rgb_data[src + 1]; + framebuffer_input[dst + 2] = fb->rgb_data[src + 2]; + } } } - - UARTprintf("Starting DMA.\n"); - kickoff_transfers(); + return len; +length_error: + UARTprintf("Invalid packet length\n"); return len; } void kickoff_transfers() { + while(MAP_uDMAChannelIsEnabled(11) + || MAP_uDMAChannelIsEnabled(25) + || MAP_uDMAChannelIsEnabled(13) + || MAP_uDMAChannelIsEnabled(15)){ + UARTprintf("A DMA tranfer is still running\n"); + /* Idle for some time to give the µDMA controller a chance to complete its job */ + SysCtlDelay(5000); + } + /* Wait 1.2ms (20kCy @ 50MHz) to ensure the WS2801 latch this frame's data */ + SysCtlDelay(20000); /* Swap buffers */ unsigned char *tmp = framebuffer_output; framebuffer_output = framebuffer_input; @@ -195,7 +200,7 @@ void kickoff_transfers() { kickoff_transfer(15, 3, SSI3_BASE); } -void kickoff_transfer(unsigned int channel, unsigned int offset, int base) { +inline void kickoff_transfer(unsigned int channel, unsigned int offset, int base) { MAP_uDMAChannelTransferSet(channel | UDMA_PRI_SELECT, UDMA_MODE_BASIC, framebuffer_output+BUS_SIZE*offset, (void *)(base + SSI_O_DR), BUS_SIZE); MAP_uDMAChannelEnable(channel); } @@ -302,8 +307,6 @@ int main(void) { MAP_SSIDMAEnable(SSI2_BASE, SSI_DMA_TX); MAP_SSIDMAEnable(SSI3_BASE, SSI_DMA_TX); - MAP_IntEnable(INT_SSI0); - /* Enable the SSIs after configuring anything around them. */ MAP_SSIEnable(SSI0_BASE); MAP_SSIEnable(SSI1_BASE); diff --git a/firmware/startup_gcc.c b/firmware/startup_gcc.c index 8c7a44d..b9284ad 100644 --- a/firmware/startup_gcc.c +++ b/firmware/startup_gcc.c @@ -43,7 +43,6 @@ static void IntDefaultHandler(void); extern void SysTickIntHandler(void); extern void UARTStdioIntHandler(void); extern void USB0DeviceIntHandler(void); -extern void SSI0IntHandler(void); //***************************************************************************** // @@ -92,7 +91,7 @@ void (* const g_pfnVectors[])(void) = IntDefaultHandler, // GPIO Port E UARTStdioIntHandler, // UART0 Rx and Tx IntDefaultHandler, // UART1 Rx and Tx - SSI0IntHandler, // SSI0 Rx and Tx + IntDefaultHandler, // SSI0 Rx and Tx IntDefaultHandler, // I2C0 Master and Slave IntDefaultHandler, // PWM Fault IntDefaultHandler, // PWM Generator 0 -- cgit