Hello,
I am unable to figure out why EPI writes are being permanently stalled after I cancel non-blocking reads. The condition that creates this situation is as follows:
1. The EPI is configured for HB8-FIFO mode of operation.
2. Non-blocking reads are used to receive bytes (only on channel #0). This works fine.
3. Some time later in the application the non-blocking reads are cancelled by this code:
HWREG(EPI0_BASE + EPI_O_RPSTD0) = 0;while ((HWREG(EPI0_BASE + EPI_O_STAT) & 0x11) == 0x10);
4. That code is followed by three writes to the EPI as follows:
volatile char * epi;epi = (char *) 0xA0000000;*epi = 'O';*epi = 'K';*epi = 13;
5. At this point the application goes off doing some other stuff (non EPI related), but no write strobes are ever detected on EPI bus. When the program is halted I read the following from the EPI registers:
EPI_STAT: 0x0000 00A0 [external FIFO is not full (bit 8 clear) and a write is in progress (bit 5 set)]
EPI_WFIFOCNT: 0x0000 0001 [1 slot left in write FIFO - because three bytes were written to it]
Unfortunately the above register values never change. It seems the external writes are permanently stalled I and am unable to figure out why.
The attached file show the contents of all the EPI registers when the program was halted.
I am probably missing something obvious but it escapes me. Thanks for any assistance you can offer.
One thing that was observed about your code segment in section 3) above. After waiting for the status to clear, you are not draining the fifo. That is the last step in the data sheet for terminating the non-blocking read mode.
If adding that doesn't address the problem, we will try to reproduce the error here. We will need more details about your hardware setup and also more details on the code that you are using to setup and access the EPI.
--Bobby
Hi Bobby,
Thanks for your reply. I added the code to clear out the RX FIFO but the problem persists. To simplify things I created a new CCSv5 project that attempts to duplicate the exact conditions without all my project's other code (RTOS, LwIP, ect). This CCSv5 project is attached (as a .zip archive).
First some hardware details. The board I have is a custom one, not a dev kit. The MCU clock source is an external 16 MHz crystal. The EPI is connected to a FIFO composed of 12 signals in total. 8 data lines, one read strobe (active low), one write strobe (active low), one FIFO full (active high), and one FIFO empty (active high).
The board also uses many other peripherals (UART, I2C, I2S, Ethernet, ect) but for the attached CCS project only the EPI is used. I also have 4 hardware debug pins connected to a scope that allows me to trace program flow.
Inside the attached CCS project zip are two pictures captured from a scope. One picture show the EPI writes occurring as desired, while the other does not show any EPI writes. In both pictures the same 8 signals are traced. They are my debug 1 to 4 GPIO outputs, EPI FIFO full, EPI write strobe, EPI FIFO empty, and EPI read strobe. (note, the pictures are also shown below).
The only code difference between the two pictures is the line (in main.c):
ROM_EPINonBlockingReadStart(EPI0_BASE, 0, 512);
If the above function call is made the EPI writes stall out and never occur. However once I comment out the above line the EPI writes happen as expected.
Here is the entire main.c file:
/* EPI <-> FIFO Test Program: * * * * main.c */ #include <stdint.h> #include "inc/hw_memmap.h" #include "inc/hw_types.h" #include "inc/hw_ints.h" #include "inc/hw_sysctl.h" #include "inc/hw_gpio.h" #include "inc/hw_epi.h" #include "driverlib/sysctl.h" #include "driverlib/gpio.h" #include "driverlib/epi.h" #include "driverlib/rom.h" // Define the hardware debug pins that can be monitored on a scope. #define DEBUG0_SET HWREG(GPIO_PORTJ_BASE + (GPIO_PIN_3 << 2)) = GPIO_PIN_3 #define DEBUG0_CLR HWREG(GPIO_PORTJ_BASE + (GPIO_PIN_3 << 2)) = 0 #define DEBUG1_SET HWREG(GPIO_PORTH_BASE + (GPIO_PIN_5 << 2)) = GPIO_PIN_5 #define DEBUG1_CLR HWREG(GPIO_PORTH_BASE + (GPIO_PIN_5 << 2)) = 0 #define DEBUG2_SET HWREG(GPIO_PORTE_BASE + (GPIO_PIN_0 << 2)) = GPIO_PIN_0 #define DEBUG2_CLR HWREG(GPIO_PORTE_BASE + (GPIO_PIN_0 << 2)) = 0 #define DEBUG3_SET HWREG(GPIO_PORTE_BASE + (GPIO_PIN_1 << 2)) = GPIO_PIN_1 #define DEBUG3_CLR HWREG(GPIO_PORTE_BASE + (GPIO_PIN_1 << 2)) = 0 //================================================================= void main(void) { // Use external 16 MHz Xtal. // Set the clocking to run at 50 MHz from the PLL. ROM_SysCtlClockSet(SYSCTL_SYSDIV_4 | SYSCTL_USE_PLL | SYSCTL_XTAL_16MHZ | SYSCTL_OSC_MAIN); // Enable and then reset the GPIO Peripherals (all banks). ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA); ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB); ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOC); ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOD); ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOE); ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF); ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOG); ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOH); ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOJ); ROM_SysCtlPeripheralReset(SYSCTL_PERIPH_GPIOA); ROM_SysCtlPeripheralReset(SYSCTL_PERIPH_GPIOB); ROM_SysCtlPeripheralReset(SYSCTL_PERIPH_GPIOC); ROM_SysCtlPeripheralReset(SYSCTL_PERIPH_GPIOD); ROM_SysCtlPeripheralReset(SYSCTL_PERIPH_GPIOE); ROM_SysCtlPeripheralReset(SYSCTL_PERIPH_GPIOF); ROM_SysCtlPeripheralReset(SYSCTL_PERIPH_GPIOG); ROM_SysCtlPeripheralReset(SYSCTL_PERIPH_GPIOH); ROM_SysCtlPeripheralReset(SYSCTL_PERIPH_GPIOJ); // Enable and then reset the external bus peripheral. ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_EPI0); ROM_SysCtlDelay(1); ROM_SysCtlPeripheralReset(SYSCTL_PERIPH_EPI0); ROM_SysCtlDelay(1); // ------------------------ // Configure GPIO - DEBUG OUTPUT PINS // Port 'E': pin 0 is DEBUG2 // pin 1 is DEBUG3 ROM_GPIOPinTypeGPIOOutput(GPIO_PORTE_BASE, GPIO_PIN_0 | GPIO_PIN_1); // Port 'H': pin 5 is DEBUG1 ROM_GPIOPinTypeGPIOOutput(GPIO_PORTH_BASE, GPIO_PIN_5); // Port 'J': pin 3 is DEBUG0 ROM_GPIOPinTypeGPIOOutput(GPIO_PORTJ_BASE, GPIO_PIN_3); // Configure the GPIO pins for EPI operation. ROM_GPIOPinConfigure(GPIO_PH3_EPI0S0); ROM_GPIOPinConfigure(GPIO_PH2_EPI0S1); ROM_GPIOPinConfigure(GPIO_PC4_EPI0S2); ROM_GPIOPinConfigure(GPIO_PC5_EPI0S3); ROM_GPIOPinConfigure(GPIO_PC6_EPI0S4); ROM_GPIOPinConfigure(GPIO_PC7_EPI0S5); ROM_GPIOPinConfigure(GPIO_PH0_EPI0S6); ROM_GPIOPinConfigure(GPIO_PH1_EPI0S7); ROM_GPIOPinConfigure(GPIO_PH6_EPI0S26); ROM_GPIOPinConfigure(GPIO_PH7_EPI0S27); ROM_GPIOPinConfigure(GPIO_PJ4_EPI0S28); ROM_GPIOPinConfigure(GPIO_PJ5_EPI0S29); // D2, D3, D4, D5 ROM_GPIOPinTypeEPI(GPIO_PORTC_BASE, GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7); // D0, D1, D6, D7, xEMPTY, xFULL ROM_GPIOPinTypeEPI(GPIO_PORTH_BASE, GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3 | GPIO_PIN_6 | GPIO_PIN_7); // nRD, nWR ROM_GPIOPinTypeEPI(GPIO_PORTJ_BASE, GPIO_PIN_4 | GPIO_PIN_5); DEBUG0_SET; // Set the EPI clock divider and operating mode. ROM_EPIDividerSet(EPI0_BASE, 5); ROM_EPIModeSet(EPI0_BASE, EPI_MODE_HB8); // Configure the host-bus 8-bit operating mode for FIFO. ROM_EPIConfigHB8Set(EPI0_BASE, EPI_HB8_MODE_FIFO | EPI_HB8_USE_TXEMPTY | EPI_HB8_USE_RXFULL | EPI_HB8_WRWAIT_2 | EPI_HB8_RDWAIT_2 | EPI_HB8_CSCFG_CS, 0); // Set address map for a peripheral size of 256 bytes mapped at 0xA000 0000; ROM_EPIAddressMapSet(EPI0_BASE, EPI_ADDR_RAM_SIZE_256B | EPI_ADDR_PER_BASE_A); // Configure the read and write FIFO levels. ROM_EPIFIFOConfig(EPI0_BASE, EPI_FIFO_CONFIG_TX_EMPTY | EPI_FIFO_CONFIG_RX_1_8); // Configure non-blocking reads on channel #0. Note, channel #1 is not used at all. ROM_EPINonBlockingReadConfigure(EPI0_BASE, 0, EPI_NBCONFIG_SIZE_8, 0); DEBUG0_SET; // At this point the EPI should be properly configured. // Kill some time (~10 us). ROM_SysCtlDelay(166); DEBUG1_SET; // Start EPI reading (channel 0) from the USB chip (up to 512 bytes). ROM_EPINonBlockingReadStart(EPI0_BASE, 0, 512); // Kill some time (~10 us). ROM_SysCtlDelay(166); // Stop EPI non-blocking reads. HWREG(EPI0_BASE + EPI_O_RPSTD0) = 0; while ((HWREG(EPI0_BASE + EPI_O_STAT) & 0x11) == 0x10); uint32_t ReadData = 0; while (HWREG(EPI0_BASE + EPI_O_RFIFOCNT) != 0) { ReadData += HWREG(EPI0_BASE + EPI_O_READFIFO); } DEBUG1_CLR; // Kill some time (~10 us). ROM_SysCtlDelay(166); DEBUG0_CLR; // Write three bytes. volatile char * epi; epi = (char *) 0xA0000000; *epi = 'O'; *epi = 'K'; *epi = 13; // Test complete. while (1) { DEBUG3_SET; DEBUG3_CLR; } }
Here is the picture where EPI writes worked: (non-blocking reads were never started)
And here is the picture where writes stalled out (non-blocking EPI reads were initiated for a short time then cancelled):
The debug0 signal goes high after configuring the GPIO but before configuring the EPI.
The debug1 signal goes high during the time non-blocking reads are active.
The debug2 signal is not used.
The debug3 signal marks the infinite loop at the end of main().
No data was ever made available for reading by the EPI. This is why FIFO EMPTY is always high.
Also...
During this test I noticed that my debug0 signal was not behaving properly after the EPI is configured. This signal is connected to pin J3 on the MCU. J3 can be used as EPI0S19, but I am not using it in that manner. Just as a simply GP output. Any ideas why the EPI seems to take control over this pin?
One other thing. Are the EPI read and write strobe glitches to be expected when configuring the peripheral?
I hope this information helps. Please let me know if you need any additional information.
Best regards,
Ralph
Ralph,
I've been able to download/build your project, and reproduce the results that you have seen/reported locally on a DK-LM3S9B96. I am still trying to work through all of the code to understand all of the possible EPI configuration options to see if there is some configuration setting missing for this mode of operation. It will likely be Monday or Tuesday next week before I am able to provide a better answer for what is happening. But I did want to let you know the current status.
Well, I guess on the plus side the condition is reproducible. Have you discovered any setting or configuration that I missed which is causing the writes to stall out? From looking at the EPI peripheral register contents I am unable to see any obvious causes.
My apologies for the delay. I am still coordinating with the IC and Apps team to determine exactly what is happening. However, I do have a tentative work-around. It involves setting the max delay to a non-zero value prior to terminating the non-blocking read operation. This has the potential of resulting in invalid data in the nbr fifo (since a timeout could occur before the nbr is terminated). So I would recommend draining the fifo of any valid data first, then implementing this modified piece of code to terminate the nbr.
// Stop EPI non-blocking reads. uint32_t ReadData = 0; ReadData = HWREG(EPI0_BASE + EPI_O_HB8CFG); ReadData &= ~EPI_HB8CFG_MAXWAIT_M; ReadData |= (1 << EPI_HB8CFG_MAXWAIT_S); HWREG(EPI0_BASE + EPI_O_HB8CFG) = ReadData; HWREG(EPI0_BASE + EPI_O_RPSTD0) = 0; while ((HWREG(EPI0_BASE + EPI_O_STAT) & 0x11) == 0x10);
ReadData = 0; while (HWREG(EPI0_BASE + EPI_O_RFIFOCNT) != 0) { DEBUG2_SET; ReadData += HWREG(EPI0_BASE + EPI_O_READFIFO); DEBUG2_CLR; } ReadData = HWREG(EPI0_BASE + EPI_O_HB8CFG); ReadData &= ~EPI_HB8CFG_MAXWAIT_M; HWREG(EPI0_BASE + EPI_O_HB8CFG) = ReadData;
Thanks for the update. I used your code above to stop the non-blocking reads and it does the trick. The writes are no longer stalled. Here is a picture of the writes occurring (signal 'nWrite' is the write stobe).
Note, the signal 'Debug1' goes low when the non-block reads are stopped.
I then modified the code slightly such that it waits for some data to be received from the non-blocking reads before cancelling it. This is the code added just before your new code to cancel the reads.
// Wait for a <CR> character to come in. uint32_t EpiReadCount = 0; while (1) { if (HWREG(EPI0_BASE + EPI_O_RFIFOCNT) != 0) { EpiReadCount++; uint32_t EpiData; EpiData = HWREG(EPI0_BASE + EPI_O_READFIFO); if (EpiData == 13) { // Got it, so exit the loop break; } } }
I setup my hardware so two bytes are present in the external FIFO for reading by the EPI. The byte values are 0x41 and 0x0D. Sadly I encounter the same write stall condition as before. Here is a picture:
The two read strobes (nRead) indicates that the EPI is reading the external FIFO. After the 2nd strobe the signal 'Debug1' goes low marking the code position where the non-blocking reads are cancelled. Unfortunately the writes never occur after this.
Somehow it seems like the EPI read strobes prevents the cancelling of the non-blocking reads.