This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

SSIAdvFrameHoldEnable() seems to have no effect

Other Parts Discussed in Thread: TM4C123GH6PM

Hi,

I'm trying to access a Flash Chip over SPI with the tm4c123gh6pm.

To read the manufacturer ID, I have to send 4 bytes during which the Chip Select line has to be low.

When just using SSIDataPut() CS goes up after each byte, my Flash doesn't like this and ignores the command.

I've seen that TivaWare includes a driver for accessing SPI flash that uses SSIAdvFrameHoldEnable() which does exactly what I want according the description - leaving the Chip Select line low after a write. Except that it doesn't work.
Using a Oscilloscope it is apparent that Chip Select is still being pulled up after every byte with the Tiva code:

void
SPIFlashInit(uint32_t ui32Base, uint32_t ui32Clock, uint32_t ui32BitRate)
{
	ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_SSI3);
	ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOD);
	ROM_GPIOPinConfigure(GPIO_PD0_SSI3CLK);
	ROM_GPIOPinConfigure(GPIO_PD1_SSI3FSS);
	ROM_GPIOPinConfigure(GPIO_PD2_SSI3RX);
	ROM_GPIOPinConfigure(GPIO_PD3_SSI3TX);
	ROM_GPIOPinTypeSSI(GPIO_PORTD_BASE, GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3);

    //
    // Configure the SPI module.
    //
    ROM_SSIConfigSetExpClk(ui32Base, ui32Clock, SSI_FRF_MOTO_MODE_0, SSI_MODE_MASTER, ui32BitRate, 8);

    //
    // Enable the advanced mode of operation, defaulting to read/write mode.
    //
    SSIAdvModeSet(ui32Base, SSI_ADV_MODE_READ_WRITE);

    //
    // Enable the frame hold feature.
    //
    SSIAdvFrameHoldEnable(ui32Base);

    //
    // Enable the SPI module.
    //
    ROM_SSIEnable(ui32Base);
}

void
SPIFlashReadID(uint32_t ui32Base, uint8_t *pui8ManufacturerID,
               uint16_t *pui16DeviceID)
{
    uint32_t ui32Data1, ui32Data2;

    //
    // Drain any residual data from the receive FIFO.
    //
    while(ROM_SSIDataGetNonBlocking(ui32Base, &ui32Data1) != 0)
    {
    }

    //
    // Set the SSI module into write-only mode.
    //
    SSIAdvModeSet(ui32Base, SSI_ADV_MODE_WRITE);

    //
    // Send the read ID command.
    //
    ROM_SSIDataPut(ui32Base, CMD_RDID);

    //
    // Set the SSI module into read/write mode.  In this mode, dummy writes are
    // required in order to make the transfer occur; the SPI flash will ignore
    // the data.
    //
    SSIAdvModeSet(ui32Base, SSI_ADV_MODE_READ_WRITE);

    //
    // Send three dummy bytes, marking the last as the end of the frame.
    //
    ROM_SSIDataPut(ui32Base, 0);
    ROM_SSIDataPut(ui32Base, 0);
    SSIAdvDataPutFrameEnd(ui32Base, 0);

    //
    // Read the first returned data byte, which contains the manufacturer ID.
    //
    ROM_SSIDataGet(ui32Base, &ui32Data1);
    *pui8ManufacturerID = ui32Data1 & 0xff;

    //
    // Read the remaining two data bytes, which contain the device ID.
    //
    ROM_SSIDataGet(ui32Base, &ui32Data1);
    ROM_SSIDataGet(ui32Base, &ui32Data2);
    *pui16DeviceID = ((ui32Data1 & 0xff) << 8) | (ui32Data2 & 0xff);
}

int main(void)
{
	SPIFlashInit(SSI3_BASE, ROM_SysCtlClockGet(), ROM_SysCtlClockGet() / 20);

	uint8_t   manufacturerID;
	uint16_t  deviceID;

	while (1) {
		SPIFlashReadID(SSI3_BASE, &manufacturerID, &deviceID);
		printf("manufacturer: %x\tdevice: %x\n", manufacturerID, deviceID);
	}
}

However if I use PIN_1 as GPIO, that is not let it be controlled by the SPI but instead toggle it manually, the chip answers my requests.

void SPI_Init(void) {
	ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_SSI3);
	ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOD);
	ROM_GPIOPinConfigure(GPIO_PD0_SSI3CLK);
        ROM_GPIOPinTypeGPIOOutput(GPIO_PORTD_BASE, GPIO_PIN_1); // manual CS
	// ROM_GPIOPinConfigure(GPIO_PD1_SSI3FSS);
	ROM_GPIOPinConfigure(GPIO_PD2_SSI3RX);
	ROM_GPIOPinConfigure(GPIO_PD3_SSI3TX);
	ROM_GPIOPinTypeSSI(GPIO_PORTD_BASE, GPIO_PIN_0 | GPIO_PIN_2 | GPIO_PIN_3); // GPIO_PIN_1
	// Configure for 4MHz SPI speed (80MHz/20=4)
	ROM_SSIConfigSetExpClk(SSI3_BASE, ROM_SysCtlClockGet(), SSI_FRF_MOTO_MODE_0, SSI_MODE_MASTER, ROM_SysCtlClockGet() / 10, 8);
	ROM_SSIEnable(SSI3_BASE);
	uint32_t tmp;
	while (ROM_SSIDataGetNonBlocking(SSI3_BASE, &tmp));
}

int main(void)
{
	SPI_Init();

	uint32_t data[4];

	while (1) {
		ROM_GPIOPinWrite(GPIO_PORTD_BASE, GPIO_PIN_1, 0); // manual Chip Select

		ROM_SSIDataPut(SSI3_BASE, CMD_RDID);
		ROM_SSIDataPut(SSI3_BASE, 0x0);
		ROM_SSIDataPut(SSI3_BASE, 0x0);
		ROM_SSIDataPut(SSI3_BASE, 0x0);

		ROM_SSIDataGet(SSI3_BASE, &data[0]);
		ROM_SSIDataGet(SSI3_BASE, &data[1]);
		ROM_SSIDataGet(SSI3_BASE, &data[2]);
		ROM_SSIDataGet(SSI3_BASE, &data[3]);

                // wait for the TX fifo to be empty
                while(!(HWREG(SSI3_BASE + SSI_O_SR) & SSI_SR_TFE));
                ROM_GPIOPinWrite(GPIO_PORTD_BASE, GPIO_PIN_1, 255); // manual Chip Select

		printf("Hello SPI World! - %x|%x|%x|%x\n", data[0], data[1], data[2], data[3]);
	}
}

The scope confirms that CS is low during the whole operation.

Is there some way to do that without this kind of hack?

  • Hello Benjamin,

    The advanced mode for accessing SPI Flash is available only on the TM4C129 devices. In this case since you have a TM4C123 device, you would need to control the FSS (PIN_1) as a GPIO to achieve the same

    Regards

    Amit

  • Amit,

    I was hoping to use SSIAdvFrameHoldEnable() on my TM4CX device to access two SSI slaves by preventing an SSI's Fss pin (connected to Slave1) from being pulled low during a data transaction to Slave2.  This is how I interpreted the function  description copied below -  that de-assert means Fss remains at a logic high the entire time.  .  I have tried calling SSIAdvFrameHoldEnable()  then writing to slave2 then calling SSIAdvFrameHoldDisable()  but it doesn't seem to work (not yet pulled out my logic analyser to confirm, just saying this based on the expected behaviour).    Am I interpreting this function's purpose correctly ?  Do I need to have configured the SSI in one of the advanced modes as currently configured as:

       SSIConfigSetExpClk(SSI1_BASE, ui32SysClock, SSI_FRF_MOTO_MODE_2, SSI_MODE_MASTER, 10000000, 16); 

    "SSIAdvFrameHoldEnable() Description:

    This function configures the SSI module to de-assert the SSIFss signal during the entire data
    transfer when using one of the advanced modes (instead of briefly de-asserting it after every
    byte). When using this mode, SSIFss can be directly controlled via SSIAdvDataPutFrameEnd()
    and SSIAdvDataPutFrameEndNonBlocking()."

     

    I hope I don't have to configure Fss as a GPIO and bit bang it too !

  • Hello Peter

    The SSI will toggle the FSS pin when a data transaction is requested. The Frame Hold defines if it will be toggled after every byte or will it be held low till the user explicitly mentions it to be de-asserted inactive high.

    Regards
    Amit
  • Thanks Amit, we are now attempting to bit bang the Fss line to SSI slave1 but it didn't work so after we debug with a logic analyser we'll report back.

    So can you confirm there is no TIVAware library  function that will temporarily disable the Fss from going low ?

    If there was I would keep Fss configured as originally with the SSI module controlling it  when TM4X writes to slave1 then during a Master write from the TM4CX to slave2 I would use that function to temporarily disable Fss (to slave1) while bit banging another GPIO line for the Fss to slave2. 

    regards

    Peter

  • Hello Peter,

    Yes, I can confirm that.

    Regards
    Amit
  • Peter John said:
    Thanks Amit, we are now attempting to bit bang the Fss line to SSI slave1 but it didn't work so after we debug with a logic analyser we'll report back.

    Bit banging of the Fss line to SSI slave 1 was successful, however turned out not to be necessary in our situation.  Even so we left it in place as it is the correct thing to do.   The problem we saw was caused by my not issuing an SSI Read for each Write command.  This left stale data in the SSI buffer.

    Amit thanks for confirming there is no TIVAware library  function that will temporarily disable the Fss from going low.