SPI comunication with k60

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

SPI comunication with k60

Jump to solution
3,673 Views
ioniriondo
Contributor I

Hi,

I'm trying to program the Kinetis K60 MCU to comunicate via SPI with an external flash memory model M25P80. This external flash memory works in two modes: CPOL=0, CPMA=0 or CPOL=1, CPMA=1.

I have never use this protocol so i would aprecciate some help developing at least the comunication protocol between both components.

0 Kudos
1 Solution
1,319 Views
Hui_Ma
NXP TechSupport
NXP TechSupport

Hi,

First of all, customer need to initialize the DSPI module.

DSPI module has two operating states: STOPPED and RUNNING. The states are independent of DSPI configuration. The default state of the DSPI is STOPPED.

The DSPI is started (DSPI transitions to RUNNING) when all of the following conditions are true:

• SR[EOQF] bit is clear

• MCU is not in the debug mode or the MCR[FRZ] bit is clear

• MCR[HALT] bit is clear

During the DSPI in RUNNING states, customer can write SPI_PUSHR register to start the SPI transfer.

The DSPI PUSH TX FIFO Register In Master Mode (SPIx_PUSHR) high 16-bit is SPI master commander, which control chip select signals; low 16-bit is SPI data. After customer write data to the SPI_PUSHR register, the SPI bus start to transfer data. The SPI bus also will start to receive the data and will load to SPI_POPR register.

When SPI works in slave mode, the SPI_PUSHR_SLAVE register provides 32 bit SPI frame operation.

Customer and easily modify previous attached example code, comments DMA related code and use code to write SPI_PUSHR regiser to start transfer. Customer also could use interrupt to control SPI_PUSHR data wrtie speed.

Wish it helps.


View solution in original post

0 Kudos
12 Replies
1,319 Views
Hui_Ma
NXP TechSupport
NXP TechSupport

Hi,

K60 DSPI module support both modes of M25P80 : CPOL=0, CPMA=0 or CPOL=1, CPMA=1.

DSPI supports Classic SPI with CPHA =0 and supports Classic SPI with CPHA = 1.

I attached an DSPI example for your reference.

Wish it helps.

1,319 Views
ioniriondo
Contributor I

Thanks.

Good example for learn how to enable the writting and initialize the SPI protocol.

But still I don't know how to send caracters and read from the flash memory, because in the example DMA is used and I'm not using this, so...

Any other example refering to a simple configuration for write to and read from this flash memory??

0 Kudos
1,320 Views
Hui_Ma
NXP TechSupport
NXP TechSupport

Hi,

First of all, customer need to initialize the DSPI module.

DSPI module has two operating states: STOPPED and RUNNING. The states are independent of DSPI configuration. The default state of the DSPI is STOPPED.

The DSPI is started (DSPI transitions to RUNNING) when all of the following conditions are true:

• SR[EOQF] bit is clear

• MCU is not in the debug mode or the MCR[FRZ] bit is clear

• MCR[HALT] bit is clear

During the DSPI in RUNNING states, customer can write SPI_PUSHR register to start the SPI transfer.

The DSPI PUSH TX FIFO Register In Master Mode (SPIx_PUSHR) high 16-bit is SPI master commander, which control chip select signals; low 16-bit is SPI data. After customer write data to the SPI_PUSHR register, the SPI bus start to transfer data. The SPI bus also will start to receive the data and will load to SPI_POPR register.

When SPI works in slave mode, the SPI_PUSHR_SLAVE register provides 32 bit SPI frame operation.

Customer and easily modify previous attached example code, comments DMA related code and use code to write SPI_PUSHR regiser to start transfer. Customer also could use interrupt to control SPI_PUSHR data wrtie speed.

Wish it helps.


0 Kudos
1,319 Views
ioniriondo
Contributor I

Sure, thanks.

Here is the code to initialize SPI and to enable writting and write data.

void SPI2_Init(void) {

   /* clock gate */

  SIM_SCGC3 |= SIM_SCGC3_SPI2_MASK;

 

  /* pin mux */

  PORTD_PCR11 &= ~PORT_PCR_MUX_MASK;

  PORTD_PCR11 |= PORT_PCR_MUX(2); //SPI2_PCS0

  PORTD_PCR12 &= ~PORT_PCR_MUX_MASK;

  PORTD_PCR12 |= PORT_PCR_MUX(2); //SPI2_SCK

  PORTD_PCR13 &= ~PORT_PCR_MUX_MASK;

  PORTD_PCR13 |= PORT_PCR_MUX(2); //SPI2_SOUT

  PORTD_PCR14 &= ~PORT_PCR_MUX_MASK;

  PORTD_PCR14 |= PORT_PCR_MUX(2); //SPI2_SIN

  /*Set SPI mode Master, Halt and Incoming data is shifted into the shift register.  */

  SPI2_MCR = SPI_MCR_MSTR_MASK | SPI_MCR_PCSIS(0x1) | SPI_MCR_HALT_MASK;

 

}

void SPI2_WriteEnable (void) {

   unsigned long u32ID;

    

  /*Commands to Flash Memory*/

  

   SPI2_CTAR0 = SPI_CTAR_FMSZ(0x7) /*| SPI_CTAR_DBR_MASK | SPI_CTAR_CPHA_MASK | SPI_CTAR_CPOL_MASK*/;

  

   SPI2_PUSHR = SPI_PUSHR_EOQ_MASK | SPI_PUSHR_PCS(0x1) | 0x06; 

  

   /*Start transmition*/

   SPI2_MCR &= ~SPI_MCR_HALT_MASK;

  

   while( !(SPI2_SR & SPI_SR_EOQF_MASK))

   {}

   SPI2_SR |=  SPI_SR_EOQF_MASK | SPI_SR_TCF_MASK ;

   SPI2_MCR |= SPI_MCR_HALT_MASK;

  

   u32ID = SPI2_POPR ;

}

Now I need to read/write SR, and write/read data. As you say if I'm right, with the "SPI2_WriteEnable" function I enable writting and I write data, in this case 06h value.

I'm thinking about implementing it with DMA, as in the example. Just one thing, what would be the read function? There is no example about this function.

Thanks

0 Kudos
1,319 Views
Hui_Ma
NXP TechSupport
NXP TechSupport

If you want to receive data, SPI master also need to start SPI transmit (dummy write). The SPI bus is full duplex, the SPI slave will send data to master. After the SPI transmit, master could get receive data at  SPI_PUSHR_SLAVE register.

You could refer previous attached example void vfnDSPI_DMA_Rx(dspi_ctl *dspi_value) funcation for more detailed info about how to receive data.

Wish it helps.

0 Kudos
1,319 Views
ioniriondo
Contributor I

Finally I'm using DMA. Verifyin with an osciloscope I see the right pulse for WritingEnable and EraseSector.

Now I'm traying to transmit data and see if it does right with the osciloscope too. I use the followin functions as in the example above.

vfnMem_Set4TXDMA(u32ptrBufAddress);

vfnMem_WriteEnable(&spi);

vfnDMA_Init_Tx();

vfnSPI_DMA(&spi);

But I don't see any pulse when doing this. The code is the same of the example code attached above.

Maybe have to change the channel or Source of the DMA?

0 Kudos
1,319 Views
Hui_Ma
NXP TechSupport
NXP TechSupport

Yes, It need to check which SPI module your are using. Different SPI module related with different DMA channels. You could find related info at chapter DMA MUX request sources at chapter 3 of Kinetis product reference manual.

Wish it helps.

0 Kudos
1,319 Views
ioniriondo
Contributor I

Yes, thanks. Changed Sources 16-17 for SPI0 to Sources 20-21 for SPI2. Mantain using channel 2.

Still not seeying pulse when transmitting data.

This is the code:

/********************************************************************/

void vfnMem_Set4TXDMA(unsigned long * u32ptrAddress) //PAGE PROGRAM

{

  unsigned char i;

*u32ptrAddress++ = SPI_PUSHR_CONT_MASK | SPI_PUSHR_PCS(0x1) | 0x0200; //opcode 02 and 1 byte of address

*u32ptrAddress++ = SPI_PUSHR_CONT_MASK | SPI_PUSHR_PCS(0x1) | 0x0000; //other 2 bytes of address

for(i=0;i<126;i++)

    {

        *u32ptrAddress++ = SPI_PUSHR_CONT_MASK | SPI_PUSHR_PCS(0x1) + i; // data to be written

    }

    *(--u32ptrAddress)  |= SPI_PUSHR_EOQ_MASK;

    *u32ptrAddress &= ~SPI_PUSHR_CONT_MASK;

}

/********************************************************************/

void vfnDMA_Init_Tx(void)

{

 

   // use dma to program the chip

    SIM_SCGC6 |= SIM_SCGC6_DMAMUX_MASK;

    SIM_SCGC7 |= SIM_SCGC7_DMA_MASK;

   

    DMA_ERQ = DMA_ERQ_ERQ2_MASK; //channel 2

    DMAMUX_CHCFG2 = DMAMUX_CHCFG_ENBL_MASK | DMAMUX_CHCFG_SOURCE(21) ; //Source 21 for SPI2 transmit

    /* Set the Source Address */

    DMA_TCD2_SADDR = (_SOFT_U32BITS)(CORE_SRAM_ADDR + 0x10 );

      /* Destination address */

    DMA_TCD2_DADDR = (_SOFT_U32BITS)&SPI2_PUSHR;

      /* Source offset disabled */

    DMA_TCD2_SOFF = 0x04;

      /* Source and Destination Modulo off, source and destination size 2 = 32 bits */

    DMA_TCD2_ATTR = DMA_ATTR_SSIZE(2) | DMA_ATTR_DSIZE(2);

      /* Transfer 4 bytes per transaction */

    DMA_TCD2_NBYTES_MLNO = 0x04;

      /* No adjust needed */

    DMA_TCD2_SLAST = 0x00;

      /* Destination offset disabled */

    DMA_TCD2_DOFF = 0x00;

      /* No link channel to channel, 1 transaction */

    DMA_TCD2_CITER_ELINKNO = DMA_CITER_ELINKNO_CITER(128);

      /* No adjustment to destination address */

    DMA_TCD2_DLASTSGA = 0x00;

     

    DMA_TCD2_BITER_ELINKNO = DMA_BITER_ELINKNO_BITER(128);

    DMA_TCD2_CSR = DMA_CSR_DREQ_MASK; //One transfer only.

}

/********************************************************************/

void vfnSPI_DMA(spi_ctl *spi_value)

{

   SPI2_MCR = SPI_MCR_MSTR_MASK | SPI_MCR_CLR_TXF_MASK |SPI_MCR_CLR_RXF_MASK | SPI_MCR_PCSIS(0x1) | SPI_MCR_HALT_MASK;

   SPI2_CTAR0 = SPI_CTAR_FMSZ(0xF) | spi_value->br | spi_value->cpha | spi_value->cpol;

   SPI2_RSER = SPI_RSER_TFFF_RE_MASK|SPI_RSER_TFFF_DIRS_MASK;

   SPI2_MCR = SPI_MCR_MSTR_MASK | SPI_MCR_PCSIS(0x1) | SPI_MCR_HALT_MASK;

  

   /*Start transmition*/

  SPI2_MCR &= ~SPI_MCR_HALT_MASK;

  while( !(SPI2_SR & SPI_SR_EOQF_MASK))

  {}

  SPI2_SR |=  SPI_SR_EOQF_MASK | SPI_SR_TCF_MASK ;

  SPI2_MCR |= SPI_MCR_HALT_MASK;

}

And this is the command order:

vfnMem_Set4TXDMA(u32ptrBufAddress);

vfnMem_WriteEnable(&spi);

vfnDMA_Init_Tx();

vfnSPI_DMA(&spi);

When the last command (vfnSPI_DMA) isn't enabled, I see the WriteEnable command pulse (06h - 00000110) with the osciloscope.

But when all commands are enabled, the osciloscope doesn't get nothing.

0 Kudos
1,319 Views
Hui_Ma
NXP TechSupport
NXP TechSupport

Hi,

Please refer attached file,which is using SPI2 module, and I could measure PTB22(DSPI2_SOUT) with data transfer signal.

I am using TWR-K40X256 board do the test.

Wish it helps.

0 Kudos
1,319 Views
ioniriondo
Contributor I

Thanks again for the code Hui_Ma,

Is almost the same that I had after modifying the first code you gave me. But still having the problem. The only difference between your code and mine, is the SPI_Init, where my SPI is defined on the Port D:

void vfnSPI_Init(void)

{

   /* clock gate */

  SIM_SCGC3 |= SIM_SCGC3_SPI2_MASK;

 

  /* pin mux */

  PORTD_PCR11 &= ~PORT_PCR_MUX_MASK;

  PORTD_PCR11 |= PORT_PCR_MUX(2); //SPI2_PCS0

  PORTD_PCR12 &= ~PORT_PCR_MUX_MASK;

  PORTD_PCR12 |= PORT_PCR_MUX(2); //SPI2_SCK

  PORTD_PCR13 &= ~PORT_PCR_MUX_MASK;

  PORTD_PCR13 |= PORT_PCR_MUX(2); //SPI2_SOUT

  PORTD_PCR14 &= ~PORT_PCR_MUX_MASK;

  PORTD_PCR14 |= PORT_PCR_MUX(2); //SPI2_SIN

  /*Set SPI mode Master, Halt and Incoming data is shifted into the shift register.  */

  SPI2_MCR = SPI_MCR_MSTR_MASK | SPI_MCR_PCSIS(0x1) | SPI_MCR_HALT_MASK;

 

  /*Setting some variables*/

  spi.br     = 0x00;

  spi.cpha   = 0x00000000;

  spi.cpol   = 0x00000000;

}

I have this sequence running every second in the main file to see clock and data signals in the oscilloscope:

  vfnMem_WriteEnable(&spi);

  vfnMem_WriteSR(0,&spi);

  vfnMem_WriteEnable(&spi);

  vfnMem_EraseSector(0,&spi);

  vfnMem_Set4TXDMA(u32ptrBufAddress);

  vfnMem_WriteEnable(&spi);

  vfnDMA_Init_Tx();

  spi.br     = 0x0c;

It goes perfect untill I introduce the DMA send function: "vfnSPI_DMA(&spi)":

  vfnMem_WriteEnable(&spi);

  vfnMem_WriteSR(0,&spi);

  vfnMem_WriteEnable(&spi);

  vfnMem_EraseSector(0,&spi);

  vfnMem_Set4TXDMA(u32ptrBufAddress);

  vfnMem_WriteEnable(&spi);

  vfnDMA_Init_Tx();

  spi.br     = 0x0c;

  vfnSPI_DMA(&spi);


Here, the program crashes and I don't see signals in the oscilloscope any more. So, something in this function may be wrong for my program, but I can't find what.


There is something that I'm forgetting to do? Maybe to enable something?


0 Kudos
1,319 Views
Hui_Ma
NXP TechSupport
NXP TechSupport

Hi,

From your descritpion, PORTD pins as SPI pins not the root cause, for you could find the signal from scope use the function vfnMem_WriteSR(0,&spi); You need to call vfnDMA_Init_Tx() function at first, then you can call  vfnDSPI_DMA(&dspi); to start SPI transfer. vfnDMA_Init_Tx() function will initialize the DMA module for SPI transfer.

Wish it helps.

0 Kudos
1,319 Views
ioniriondo
Contributor I

Finally found the problem. While debuging, I saw that it wents into DMA function but it kepts blocked in the "while". So I disabled the DMA to get out the function:

void vfnSPI_DMA(spi_ctl *spi_value)

{

   SPI2_MCR = SPI_MCR_MSTR_MASK | SPI_MCR_CLR_TXF_MASK |SPI_MCR_CLR_RXF_MASK | SPI_MCR_PCSIS(0x1) | SPI_MCR_HALT_MASK;

   SPI2_CTAR0 = SPI_CTAR_FMSZ(0xF) | spi_value->br | spi_value->cpha | spi_value->cpol;

   SPI2_RSER = SPI_RSER_TFFF_RE_MASK|SPI_RSER_TFFF_DIRS_MASK;

   SPI2_MCR = SPI_MCR_MSTR_MASK | SPI_MCR_PCSIS(0x1) | SPI_MCR_HALT_MASK;

 

   /*Start transmition*/

  SPI2_MCR &= ~SPI_MCR_HALT_MASK;

  while( !(SPI2_SR & SPI_SR_EOQF_MASK))

  {}

  SPI2_SR |=  SPI_SR_EOQF_MASK | SPI_SR_TCF_MASK ;

  SPI2_MCR |= SPI_MCR_HALT_MASK;

  //Disables DMA

  SPI2_RSER &= ~SPI_RSER_TFFF_RE_MASK;

  SPI2_RSER &= ~SPI_RSER_TFFF_DIRS_MASK;

}

0 Kudos