Hello All,
I am using LogicPD Omap L138 SOM on a custom board, SysBios 6.34.2.18, XDCTools 3.23.5.61, StarterWare 1.10.03.03.
I am trying to communicate with two sensors trough SPI0 bus (different CS) over the ARM9 core.
SPI freq is between 1.25Mhz to 10Mhz (the problem remains the same).
The sensors protocol is as follows:
1. GPIO trigger indicated that data can be read,
2. When data is ready bring CS down (ACTIVE state)
3. Read 2 words (16bit each) from the bus.
4. Wait for 1.
When working with only one device, this works perfectly but when I add the second device here's what happens:
After several milliseconds of good communication with both sensors, one of the devices interrupt occurs before the other finished sending the data so it takes over the CS line and this is the end for the first device communication and the second keeps on running.
Here is the device protocol:
Here is an image from the logic analyzer when things goes sour:
(D0-SCLK, D1-SOMI, D2-SIMO, D3-CS4, D4-VD4, D5-CS5, D6-VD6)
You can see here that D4 doesn't go HIGH anymore and that D5 interrupts D3 in the middle of the communication (Only 1 word was transferred).
I tried using Gate HWI but I keep missing interrupts and the data is corrupted.
I don't know how to make D5 wait for D3 to finish, I tried making D3 finish the job before\after D5 work, that makes D4 go HIGH again but I miss interrupts again and the data is corrupted.
Here is some of my code (consider it working compiled code):
Void InitSpi0(Void) { /* Enable power to SPI0. */ PSCModuleControl( SOC_PSC_0_REGS , HW_PSC_SPI0 , PSC_POWERDOMAIN_ALWAYS_ON , PSC_MDCTL_NEXT_ENABLE ) ; /* * NOTE: GP0[14] <-> J5p4 <-> SENSOR #1p1-MCLK, set PINMUX0, bit #7 : {GP0[14],I/O} * GP0[09] <-> J6p8 <-> SENSOR #2p10-VD, set PINMUX0, bit #9 : {GP0[09],I/O} * GP0[10] <-> J6p4 <-> SENSOR #2p1-MCLK, set PINMUX0, bit #23: {GP0[10],I/O} */ HWREG(SOC_SYSCFG_0_REGS + SYSCFG0_PINMUX(0)) = 0x08800080 ; /* force GP0[14] as output, clear the bit */ GPIODirModeSet(SOC_GPIO_0_REGS, SENS0_RST_PIN, GPIO_DIR_OUTPUT) ; /* force GP0[10] as output, clear the bit */ GPIODirModeSet(SOC_GPIO_0_REGS, SENS1_RST_PIN, GPIO_DIR_OUTPUT) ; /* force GP0[14] set to high */ GPIOPinWrite (SOC_GPIO_0_REGS, SENS0_RST_PIN, GPIO_PIN_HIGH ) ; /* force GP0[10] set to high */ GPIOPinWrite (SOC_GPIO_0_REGS, SENS1_RST_PIN, GPIO_PIN_HIGH ) ; /* * NOTE: GP2[15] <-> J5p6 <-> SENSOR #1p10-VD, set PINMUX5, bit #3: {GP2[15],I/O} */ HWREG(SOC_SYSCFG_0_REGS + SYSCFG0_PINMUX(5)) |= 0x00000008 ; /* force GP2[15] as input */ GPIODirModeSet(SOC_GPIO_0_REGS, SENS0_VD_PIN, GPIO_DIR_INPUT ) ; /* force GP2[14] as input */ GPIODirModeSet(SOC_GPIO_0_REGS, SENS1_VD_PIN, GPIO_DIR_INPUT ) ; /* Configure rising edge and falling edge triggers on pin GP2[15] * to generate interrupt */ GPIOIntTypeSet(SOC_GPIO_0_REGS, SENS0_VD_PIN, GPIO_INT_TYPE_FALLEDGE) ; /* Configure rising edge and falling edge triggers on pin GP0[09] * to generate interrupt */ GPIOIntTypeSet(SOC_GPIO_0_REGS, SENS1_VD_PIN, GPIO_INT_TYPE_FALLEDGE) ; /* Performing the Pin Multiplexing for SPI #0: * enable pins: {SPI0_CLK, _SPI0_SIMO, SPI0_SOMI, SPI0_ENA} */ SPIPinMuxSetup(0) ; /* select Chip Select(CS) 5 of SPI0 */ SPI0CSPinMuxSetup(SENS0_CS) ; /* select Chip Select(CS) 4 of SPI0 */ SPI0CSPinMuxSetup(SENS1_CS) ; /* Configuring and enabling the SPI1 instance. */ SetupSpi() ; Error_Block eb; Error_init(&eb); myHwi = Hwi_create(SYS_INT_SPINT0, SPIIsr, NULL, &eb); if (myHwi == NULL) { System_abort("Hwi create failed"); } } /* ** Configures SPI Controller ** */ Void SetupSpi(Void) { unsigned char dcs = SENS0_CS_WRD | SENS1_CS_WRD ; unsigned int frmt_ind = SPI_DATA_FORMAT0 ; // SPI0_CS[0x30] /* reset state SPI0, SPI_BASE = 0x01C41000 (for SPI #0) */ SPIReset(SPI_BASE) ; /* out of reset state SPI0 */ SPIOutOfReset(SPI_BASE) ; /* set SPI0 to MASTER_MODE and SPIx_CLK is configured to output */ SPIModeConfigure(SPI_BASE, SPI_MASTER_MODE) ; /* set SPI_DATA_FORMAT0.PRESCALARE = (moduleClk/spiClk) - 1, other bits of * SPI_DATA_FORMAT0 are cleared. */ SPIClkConfigure( SPI_BASE , ARM_CLK_RATE_IN_HZ>>1 , SPI_CLK_RATE_IN_HZ , SPI_DATA_FORMAT0 ) ; /* set SPIPC0 with val: CS#5 active, SPI0_ENA not active (GPIO), * {CLKFUN, SIMOFUN, SOMIFUN, ENAFUN} active */ //SPIPinControl(SPI_BASE, 0, 0, &val) ; HWREG(SPI_BASE + SPI_SPIPC(0)) = 0x0 ; HWREG(SPI_BASE + SPI_SPIPC(0)) |= SPIPC0_SOMIFUN_MSK(1) ; HWREG(SPI_BASE + SPI_SPIPC(0)) |= SPIPC0_SIMOFUN_MSK(1) ; HWREG(SPI_BASE + SPI_SPIPC(0)) |= SPIPC0_CLKFUN_MSK(1) ; HWREG(SPI_BASE + SPI_SPIPC(0)) |= SPIPC0_SCS0FUN_MSK(dcs) ; /* set SPIDEF with dcs: CS#5 and CS#4 defualt "1" logic when inactive */ SPIDefaultCSSet(SPI_BASE, dcs) ; /* * set SPI_DATA_FORMAT0.POLARITY = 1, SPI clock signal is high-inactive. * set SPI_DATA_FORMAT0.SHIFTDIR = 0, MSB shift out first. * set SPI_DATA_FORMAT0.CHARLEN = 0x10, 16 bit shift register. */ SPIConfigDataFmtReg(frmt_ind) ; /* set SPI_SPILVL.TXINTLVL = 1, tx interrupt mapped to INT1. * set SPI_SPILVL.RXINTLVL = 1, rx interrupt mapped to INT1. */ SPIIntLevelSet( SPI_BASE, SPI_RECV_INTLVL | SPI_TRANSMIT_INTLVL) ; /* set SPI_SPIPC1.SCS0DIR[4] = 1, SPI0_SCS[4] pin is an output. * set SPI_SPIPC1.SCS0DIR[5] = 1, SPI0_SCS[5] pin is an output. * set SPI_SPIPC1.SPIx_CLK = 1, SPI0_CLK pin is an output. * set SPI_SPIPC1.SIMODIR = 1, SPI0 SIMO pin is output. */ //HWREG(SPI_BASE + SPI_SPIPC(1)) |= 0x00000600 ; /* set SPI_SPIGCR1.ENABLE = 1, Enable SPI0 communication. */ SPIEnable( SPI_BASE ) ; } void ReceiveDataNoEdma(unsigned int baseAdd, unsigned short length, short *buffer, UInt8 *read, UInt64 *idx) { int i; for(i=0;i<length;i++) { //while((HWREG(baseAdd + SPI_SPIBUF) & SPI_SPIBUF_TXFULL)); SPITransmitData1(baseAdd, 0); while(!(HWREG(baseAdd + SPI_SPIBUF) & SPI_SPIBUF_RXEMPTY)); *buffer = (short)SPIDataReceive(baseAdd); buffer++; (*read)--; (*idx)++; } } /* ** Send SPI command to slave ** */ void SendCommand(unsigned int baseAdd, unsigned char cs, unsigned short command) { SPIDat1Config(baseAdd, (SPI_CSHOLD | SPI_DATA_FORMAT0), (1<<cs)); while((HWREG(baseAdd + SPI_SPIBUF) & SPI_SPIBUF_TXFULL)); SPITransmitData1(baseAdd, command); SPIDat1Config(baseAdd, SPI_DATA_FORMAT0, (1<<cs)); } /* ** Configures Data Format register of SPI ** */ static void SPIConfigDataFmtReg(unsigned int dataFormat) { /* Configures the polarity and phase of SPI clock */ SPIConfigClkFormat(SPI_BASE, (SPI_CLK_POL_HIGH | SPI_CLK_INPHASE), dataFormat); /* Configures SPI to transmit MSB bit First during data transfer */ SPIShiftMsbFirst(SPI_BASE, dataFormat); /* Sets the Charcter length */ SPICharLengthSet(SPI_BASE, CHAR_LENGTH, dataFormat); }
void GPIOBank2Isr(void) { /* Clears the system interrupt status of GPIO in AINTC.*/ IntSystemStatusClear(SYS_INT_GPIOB2); GPIOPinIntClear(SOC_GPIO_0_REGS, SENS0_VD_PIN); if(isAvail0) Read0(2, FALSE); } void GPIOBank0Isr(void) { /* Clears the system interrupt status of GPIO in AINTC.*/ IntSystemStatusClear(SYS_INT_GPIOB0); GPIOPinIntClear(SOC_GPIO_0_REGS, SENS1_VD_PIN); if(isAvail1) Read1(2, FALSE); } Int8 Read0(UInt16 length, Bool isSecond) { if(length==0) return 1; short *buff; readA = length; // Check if other sensor is at work /*unsigned long csStat = HWREG(SENS1_SPI_REGS + SPI_SPIPC(2)); Bool isActive = !(HWREG(SENS1_SPI_REGS + SPI_SPIPC(2)) & (1 << SENS1_CS)); if(isActive && readB>0) { errB++; Read1(readB, TRUE); }*/ //gateKey = GateHwi_enter(gateHwi0); SPIDat1Config(SENS0_SPI_REGS, (SPI_CSHOLD |SPI_DATA_FORMAT0), (1<<SENS0_CS)); ReceiveDataNoEdma(SENS0_SPI_REGS, length, &buff[current], &readA, &idxA); NOP; SPIDat1Config(SENS0_SPI_REGS, (SPI_DATA_FORMAT0), (1<<SENS0_CS)); //GateHwi_leave(gateHwi0, gateKey); } Int8 Read1(UInt16 length, Bool isSecond) { if(length==0) return 1; short *buff; readB = length; // Check if other sensor is at work /*unsigned long csStat = HWREG(SENS0_SPI_REGS + SPI_SPIPC(2)); Bool isActive = !(HWREG(SENS0_SPI_REGS + SPI_SPIPC(2)) & (1 << SENS0_CS)); if(isActive && readA>0) { errA++; Read0(readA, TRUE); }*/ //gateKey = GateHwi_enter(gateHwi0); SPIDat1Config(SENS1_SPI_REGS, (SPI_CSHOLD | SPI_DATA_FORMAT0), (1<<SENS1_CS)); ReceiveDataNoEdma(SENS1_SPI_REGS, length, &buff[current], &readB, &idxB); NOP; SPIDat1Config(SENS1_SPI_REGS, (SPI_DATA_FORMAT0), (1<<SENS1_CS)); //GateHwi_leave(gateHwi0, gateKey); }
The devices are a black box and cannot be changed, I can start the streaming at different times but eventually the same thing happens.
Why is it taking 15us for the SPI to start the transfer after the GPIO trigger (I checked and the code doesn't take so long)?
Sorry for the long post but I'm really frustrated so I would appreciate your help.
Thanks,
Yoel