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?