AnsweredAssumed Answered

How to use KSDK 1.1.0 SPI Master driver to read/write Microwire(tm) EEPROM?

Question asked by Scott Whitney on Apr 28, 2015
Latest reply on May 7, 2015 by Jorge_Gonzalez

Hello folks,

 

I am using a K60 tower, KSDK 1.1.0, and IAR Embedded Workbench for Cortex-M 7.40.2.  I am trying to figure out how to use the provided DSPI Master Driver code to read from/write to an ST Micro M93C46, which is a 1-Kbit EEPROM (128 bytes or 64 16-bit words) using a Microwire(tm) interface.

 

The M93C46 is configured to be organized as "by word" (x16 bits), so the ORG line on the part is pulled high.  The data sheet for the part indicates the following:

 

- Each instruction is preceded by a rising edge on Chip Select Input (S) with Serial Clock (C) being held low.

- A start bit, which is the first '1' read on Serial Data Input (D) during the rising edge of Serial Clock (C).

- Two opcode bits, read on the Serial Data Input (D) during the rising edge of Serial Clock (C)

- The address bits of the byte or word that is to be accessed (6 bits for x16 organization)

 

For example, a Read Data from Memory would have a Start Bit (1b), and Opcode (10b), the starting address (A5-A0, 6 bits), then 16 bits of data (D15-D0), for a total of 25 required clock cycles.  I just can't figure out how to set up and use the DSPI Master Driver to perform this transfer or transfers, and need some help.

 

I have PTD0, 1, 2, and 3 configured as Alt2 to configure them for SPI0 use.  This assigns the following pins:

PTD0 -> SPI0_PCS0, PTD1 ->SPI0_SCK, PTD2 ->SPI0_SOUT, and PTD3 -> SPI0_SIN.  This is accomplished via some code I found in an example pin_mux.c using HW_SPI0 as the instance:

 

void configure_spi_pins(uint32_t instance)

{

    switch(instance)

    {

    case HW_SPI0:                       /* SPI0 */

        /* Affects PORTD_PCR0 register */

        PORT_HAL_SetMuxMode(PORTD_BASE,0u,kPortMuxAlt2);

        /* Affects PORTD_PCR3 register */

        PORT_HAL_SetMuxMode(PORTD_BASE,3u,kPortMuxAlt2);

        /* Affects PORTD_PCR1 register */

        PORT_HAL_SetMuxMode(PORTD_BASE,1u,kPortMuxAlt2);

        /* Affects PORTD_PCR2 register */

        PORT_HAL_SetMuxMode(PORTD_BASE,2u,kPortMuxAlt2);

        break;

 

We wired up a sample M93C46 on one of the TWR-PROTO boards, and it seems to be connected to the correct pins.

 

I read the documentation for the DSPI Master Driver, and it appears that I need to make calls to DSPI_DRV_MasterInit() and DSPI_DRV_MasterConfigureBus() to set up the user configuration and the bus configuration respectively, but some of the parameters are not clear to me. 

 

Initially I need to set a single Start bit (1b), then the 2-bit Read opcode (10b), then the starting address (let's assume we start at 0 to make it easy, so A5-A0 is (000000b).  Then I need to clock another 16 times to transfer the actual data. 

 

To make things a bit more difficult, the data sheet indicates that for the first word, a dummy 0 bit is output first, followed by the 16-bit word, MSB first.  Output data changes are triggered by the rising edge of Serial Clock (C).  As long as Chip Select (S) is held high, we can continue to clock out the next words, and a dummy 0 bit is NOT output between words, so you can read a continuous stream of data.

 

Here's where I get lost.  The examples show that I need to call DSPI_DRV_MasterInit() first, so I tried the following:

 

    dspi_master_state_t dspiMasterState;

    uint32_t calculatedBaudRate;

    dspi_master_user_config_t userConfig;

   

    // Set up the user configuration

    userConfig.isChipSelectContinuous = false; 

    userConfig.isSckContinuous        = false;

    userConfig.pcsPolarity            = kDspiPcs_ActiveHigh;

    userConfig.whichCtar              = kDspiCtar0;

    userConfig.whichPcs               = kDspiPcs0;

 

    // Initialize the DSPI module

    DSPI_DRV_MasterInit(HW_SPI0, &dspiMasterState, &userConfig);

 

I have a feeling that the .isChipSelectContinuous field needs to be true, but set that aside for now.  I believe that I next have to configure the bus, which is done in the following example:

 

    dspi_device_t spiDevice;

    spiDevice.dataBusConfig.bitsPerFrame = ???; // What to put here?

    spiDevice.dataBusConfig.clkPhase = kDspiClockPhase_FirstEdge;   // What does this do?

    spiDevice.dataBusConfig.clkPolarity = kDspiClockPolarity_ActiveHigh;

    spiDevice.dataBusConfig.direction = kDspiMsbFirst;

    spiDevice.bitsPerSec = 50000;   // Can go faster, up to 2 MHz

    DSPI_DRV_MasterConfigureBus(instance, &spiDevice, &calculatedBaudRate);

 

Since I need to transfer a 1-bit Start bit, followed by 2 bits of opcode and 6 bits of address, then somehow get 17 bits of data for the first word (because of the dummy 0 bit and then as many other 16-bit words as I need (without the dummy 0 bit), what should the bitsPerFrame be set to?

 

Further, how should I set up the actual data blocks/frames to be transferred and received?  Eventually I will probably want to use a non-blocking Transfer call to do this, but an example with a blocking call would be fine for now.

 

Has anyone else run into using the DSPI interface on the K60 with variable-length transfers?  What's the best way to handle them, preferably using the KSDK drivers?

 

Many thanks, and please let me know if you need any clarification.  It's a hard question to write briefly!

 

--Scott

Outcomes