Spi connection with mlx75306

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

Spi connection with mlx75306

3,455 Views
lucasmahieu
Contributor III

Hey,

I have a problem creating a connection between my FRDM kl25z and a linear camera mlx75306.

The things I don't understand is that the kl25z has only one data buffer : for receiving and sending data.

But on the mlx75306 datasheet, the camera can send data when receiving data from the kl25z. 

So how the kl25z can get the data received when it is sending others ?

 Does any body know more about it to help me ?

thanks before 

0 Kudos
12 Replies

3,028 Views
jeremyzhou
NXP Employee
NXP Employee

Hi mahieu lucas,

Thanks for your reply, and please have a try with the adapted code below.

void dma_init(void){

// Enable clocks
SIM_SCGC6 |= SIM_SCGC6_DMAMUX_MASK;
SIM_SCGC7 |= SIM_SCGC7_DMA_MASK;
  /* disable chl first */
DMA_DCR0 &= ~DMA_DCR_ERQ_MASK;

/* dma chl source config */
DMAMUX0_CHCFG0 |= DMAMUX_CHCFG_SOURCE(16);

// transfert de 3 octets via DMA 

DMA_DSR_BCR0 = DMA_DSR_BCR_BCR(3);


// Configure DMA
DMA_SAR0 = (uint32_t) &SPI0_D;

DMA_DCR_SSIZE(1) | // Set source size to 8 bits


DMA_DAR0 = (uint32_t) &spi_rdata;

DMA_DCR_DSIZE(1)); // Set destination size of 8 bits


/* cycle steal */

DMA_DCR0 |= (DMA_DCR_CS_MASK);

    /* defaut: enable auto disable req */

DMA_DCR0 |= (DMA_DCR_D_REQ_MASK);

/* enable chl */

DMAMUX0_CHCFG0 |=DMAMUX_CHCFG_ENBL_MASK;


DMA_DCR0 |= DMA_DCR_ERQ_MASK;;


// Enable interrupt
enable_irq(INT_DMA0 - 16);
}

Have a great day,
Ping

 

-----------------------------------------------------------------------------------------------------------------------
Note: If this post answers your question, please click the Correct Answer button. Thank you!
-----------------------------------------------------------------------------------------------------------------------

0 Kudos

3,028 Views
lucasmahieu
Contributor III

Hey Jeremy, 

I am confused because I do't succeed to make my SPI connection working with DMA... 

You gave me so many advice, but I steel have problems.

here my code : 

The main.c

int main(void){
     volatile int it = 0;

     dma_init();

     for(it=0;it <100000;it++);

     SPI_init();

     camera_send_cmd(CR,0,0);

     for(it=0;it <100000;it++);

     camera_send_cmd(WU,0,0);

     TERMINAL_PRINTF("START TEST\n\r");

     while(1) {

          test_RT();

          for(it=0;it <100000;it++);
     }
     return 0;
}
‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

The test_RT fonction: 

extern uint8_t spi_rdata[3]={0xf};
#define RT 0b11000011
void test_RT(){
     volatile int i=0;
     uint8_t read[3]={RT,0x00,0x00};
     TERMINAL_PRINTF("TEST_RT - new_dma_data=%u\n\r",new_dma_data);
     
        SPI_write(read,3);

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

     if(new_dma_data){
          TERMINAL_PRINTF("SB=%u\n\r",spi_rdata[0]);
          TERMINAL_PRINTF("Threshold=%u\n\r",spi_rdata[1]);
          TERMINAL_PRINTF("Zero=%u\n\r",spi_rdata[2]);
          TERMINAL_PRINTF("----------------\n\r");
     }
}‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

I will give you me 2 init fonction : 

volatile uint8_t new_dma_data=0;

void DMA_IRQHandler(void){
     static uint8_t nb_int = 0;
     nb_int =;
     if(nb_int%3==0){
       // Clear pending errors and/or the done bit 
       if (((DMA_DSR_BCR0 & DMA_DSR_BCR_DONE_MASK) == DMA_DSR_BCR_DONE_MASK)
               | ((DMA_DSR_BCR0 & DMA_DSR_BCR_BES_MASK) == DMA_DSR_BCR_BES_MASK)
               | ((DMA_DSR_BCR0 & DMA_DSR_BCR_BED_MASK) == DMA_DSR_BCR_BED_MASK)
               | ((DMA_DSR_BCR0 & DMA_DSR_BCR_CE_MASK) == DMA_DSR_BCR_CE_MASK))
          DMA_DSR_BCR0 |= DMA_DSR_BCR_DONE_MASK;

       DMA_SAR0 = (uint32_t) &SPI0_D;
       DMA_DAR0 = (uint32_t) &spi_rdata;
       DMA_DSR_BCR0 |= DMA_DSR_BCR_BCR(3);
       DMA_DCR0 |= DMA_DCR_ERQ_MASK;

       new_dma_data++;
     }
     TERMINAL_PRINTF("IRQ_DMA\n");
}

void dma_init(void){

     new_dma_data=0;
     // Enable clocks
     SIM_SCGC6 |= SIM_SCGC6_DMAMUX_MASK;
     SIM_SCGC7 |= SIM_SCGC7_DMA_MASK;

     // Config DMA Mux for ADC operation
     // Disable DMA Mux channel first
     DMAMUX0_CHCFG0 = 0x00;

     // Clear pending errors and/or the done bit 
     if (((DMA_DSR_BCR0 & DMA_DSR_BCR_DONE_MASK) == DMA_DSR_BCR_DONE_MASK)
               | ((DMA_DSR_BCR0 & DMA_DSR_BCR_BES_MASK) == DMA_DSR_BCR_BES_MASK)
               | ((DMA_DSR_BCR0 & DMA_DSR_BCR_BED_MASK) == DMA_DSR_BCR_BED_MASK)
               | ((DMA_DSR_BCR0 & DMA_DSR_BCR_CE_MASK) == DMA_DSR_BCR_CE_MASK))
          DMA_DSR_BCR0 |= DMA_DSR_BCR_DONE_MASK;

     // Configure DMA
     DMA_SAR0 = (uint32_t) &SPI0_D;
     DMA_DAR0 = (uint32_t) &spi_rdata;
     DMA_DSR_BCR0 = DMA_DSR_BCR_BCR(3); // transfert de 3 octets via le DMA

     // Clear Source size and Destination size fields.  
     DMA_DCR0 &= ~(DMA_DCR_SSIZE_MASK | DMA_DCR_DSIZE_MASK);

     DMA_DCR0 |= DMA_DCR_DSIZE(1);     // Set destination size of 8 bits 
     DMA_DCR0 |= DMA_DCR_SSIZE(1);     // Set source size to 8 bits
     DMA_DCR0 |= DMA_DCR_DINC_MASK;     // Set increments to destination address
     DMA_DCR0 |= DMA_DCR_DMOD(1);     // destination adress modulo 16 bytes
     DMA_DCR0 |= DMA_DCR_CS_MASK;     // 1 transfert per request 
     DMA_DCR0 |= DMA_DCR_EINT_MASK;     // Enable interrupt

     // Enable DMA channel and source
     // Enable DMA channel and set SPI0 receive as source cf doc KL25P80M48SF0RM.pdf p64-65
     DMAMUX0_CHCFG0 |= DMAMUX_CHCFG_ENBL_MASK | DMAMUX_CHCFG_SOURCE(16); 

     DMA_DCR0 |= DMA_DCR_ERQ_MASK; // Enable peripheral request

     // Enable interrupt
     enable_irq(INT_DMA0 - 16);
}‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

and for the spi :

uint8_t spi_rdata[3]={0xFF};

void SPI_init(void) {
     // Enable clock network to SPI0
     SIM_SCGC4 |= SIM_SCGC4_SPI0_MASK;
     SIM_SCGC5 |= SIM_SCGC5_PORTC_MASK;
     SIM_SCGC5 |= SIM_SCGC5_PORTD_MASK;
     
     PORTD_PCR0 = PORT_PCR_MUX(2);  // PCS
     PORTC_PCR5 = PORT_PCR_MUX(2);  // SCK
     PORTC_PCR6 = PORT_PCR_MUX(2);  // MOSI
     PORTC_PCR7 = PORT_PCR_MUX(2);  // MISO
     
     // disable SPI
     SPI0_C1 &= ~SPI_C1_SPE_MASK;

     SPI0_C1 = SPI_C1_MSTR_MASK | SPI_C1_SSOE_MASK | SPI_C1_CPHA_MASK | SPI_C1_CPOL_MASK;   
     
     SPI0_C2 = SPI_C2_MODFEN_MASK;   //Master SS pin acts as slave select output     

     // Pour activer le DMA en réception
     SPI0_C2 |= SPI_C2_RXDMAE_MASK;

     SPI0_BR = (SPI_BR_SPPR(0b000) | SPI_BR_SPR(0b0011));     
     
     SPI0_C1 |= SPI_C1_SPE_MASK;          /* Enable SPI module */
}

void SPI_write(uint8_t* p, uint8_t size) {
     uint8_t i=0;
     for (i=0; i<size; i++) {
          while(!(SPI_S_SPTEF_MASK & SPI_status));
          SPI0_D = p[i];
     }
}

sorry for the french comment in the code ^^

I give you lot of work, but your help would be very very very useful because I really donc understand what is the problem.

I use an oscilloscope to see the signal. All signal are right the MOSI, the MISO also.

BUT : 

-> if the interrupt of the DMA is disable (DMA_DCR_EINT_MASK not used), all works fine. But I receive 0 in spi_rdata[0], 0 in spi_rdata[1], 0 in spi_rdata[2]. I initialise spi_rdata[] with 0xFF, and in the printf I can see that there are 0 in spi_rdata[i]. But the problem is that on MISO I don't have 0 ... So Why ? Really don't understand this point.

-> if I enable the interrupt in the DMA init : the spi_write() is blocking. The program block in the spi_write fonction I donc know why ... 

REALLY thanks in advance ! 

0 Kudos

3,028 Views
lucasmahieu
Contributor III

Hey, 

With oscilloscope I succeed to see that I send the right command byte to the mlx.

I receive some data from the mlx, but I don't succeed to get it. 

Can you look at my dam_init, because the software is blocking on the "enable_irq(INT_DMA0 - 16);" fonction call.

void dma_init(void){

new_dma_data=0;
// Enable clocks
SIM_SCGC6 |= SIM_SCGC6_DMAMUX_MASK;
SIM_SCGC7 |= SIM_SCGC7_DMA_MASK;

// Config DMA Mux for ADC operation
// Disable DMA Mux channel first
DMAMUX0_CHCFG0 = 0x00;

// Configure DMA
DMA_SAR0 = (uint32_t) &SPI0_D;
DMA_DAR0 = (uint32_t) spi_rdata;
DMA_DSR_BCR0 = DMA_DSR_BCR_BCR(3); // transfert de 3 octets via le DMA

DMA_DCR0 |= (DMA_DCR_EINT_MASK| // Enable interrupt
DMA_DCR_ERQ_MASK | // Enable peripheral request
DMA_DCR_SSIZE(1) | // Set source size to 8 bits
DMA_DCR_DINC_MASK| // Set increments to destination address
DMA_DCR_DSIZE(1)); // Set destination size of 8 bits


// Enable DMA channel and source
DMAMUX0_CHCFG0 |= DMAMUX_CHCFG_ENBL_MASK | DMAMUX_CHCFG_SOURCE(16); // Enable DMA channel and set SPI0 receive as source cf doc KL25P80M48SF0RM.pdf p64-65


// Enable interrupt
enable_irq(INT_DMA0 - 16);
}

thanks in advance 

lucas

0 Kudos

3,028 Views
jeremyzhou
NXP Employee
NXP Employee

Hi mahieu lucas,

The DMA operation is a good approach instead of the polling method to receive the data.

The DMA operation would work automatically without any processor intervention after has been configured.

Please have a try.
Have a great day,
Ping

-----------------------------------------------------------------------------------------------------------------------
Note: If this post answers your question, please click the Correct Answer button. Thank you!
-----------------------------------------------------------------------------------------------------------------------

0 Kudos

3,028 Views
lucasmahieu
Contributor III

Hi, it is a great idea for performance. I will try to configure DMA, but I never did it. Any advice ? or exemple ? 

There is something I don't understand : why this doesn't work ? 

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

{

        while(!(SPI0_S & SPI_S_SPTEF_MASK ) );

SPI0_D = pWrite[i];

        while(!(SPI0_S & SPI_S_SPRF_MASK ) );

pRead[i] = SPI0_D;

}

I don't understand why this is not enough to get the data received by my peripheral 

0 Kudos

3,028 Views
jeremyzhou
NXP Employee
NXP Employee

Hi mahieu lucas,

Firstly, I'd highly recommend you to use the logic analyzer or oscilloscope to capture the wave when KL27 communicate with the mlx75306, then you can figure out the root cause of the issue.

Next, you can find the DMA demo in the KSDK and you can install it by refer to the thread: How to: install KSDK 2.0
Have a great day,
Ping

-----------------------------------------------------------------------------------------------------------------------
Note: If this post answers your question, please click the Correct Answer button. Thank you!
-----------------------------------------------------------------------------------------------------------------------

0 Kudos

3,028 Views
jeremyzhou
NXP Employee
NXP Employee

Hi,

The SPI sending and receiving channel are independent, they both have own data buffer and shift register.

Hope it helps,
Have a great day,

Ping

-----------------------------------------------------------------------------------------------------------------------
Note: If this post answers your question, please click the Correct Answer button. Thank you!
-----------------------------------------------------------------------------------------------------------------------

0 Kudos

3,028 Views
lucasmahieu
Contributor III

Hey,

thanks for your reply.

But why in the datasheet of kl25 it is written that the spi(x)_D register is used to send AND to receive data ?

0 Kudos

3,030 Views
jeremyzhou
NXP Employee
NXP Employee

Hi,

The SPI_D register is both the input and output register for SPI data. A write to the register
writes to the transmit data buffer, allowing data to be queued and transmitted. Data can be read from the SPI data register any time after SPRF is set and before another transfer is finished. However inside the SPI module, it has two sub components to support transmit and receive data respectively.
Hope it helps.

Have a great day!

Ping

-----------------------------------------------------------------------------------------------------------------------
Note: If this post answers your question, please click the Correct Answer button. Thank you!
-----------------------------------------------------------------------------------------------------------------------

0 Kudos

3,031 Views
lucasmahieu
Contributor III

Hey jeremy,

thanks a lot for your reply !

I think i have understand, but my code doesn't work anyway ... 

I give you my code that send 3 Bytes and receive 3Bytes. 

I have tried to send the 3 Bytes and then after to read the 3 Bytes, doesn't work.

So i tried to send the 1 Bytes and then after to read the 1 Bytes, and so one 3 times.


for (i=0; i<3; ++i) {
   while(!(SPI_S_SPTEF_MASK & SPI_status)) {
      asm("nop"); //While buffer is not empty do nothing
   }
   SPI0_D = cmd[i];
   while (!(SPI_status & SPI_S_SPRF_MASK )){
      asm("nop"); //While buffer is not full do nothing
   }
   data[i] = SPI0_D;

}
 

Some one have an idea or an implementation to propose ? 

Best regards

0 Kudos

3,031 Views
jeremyzhou
NXP Employee
NXP Employee

Hi mahieu lucas,

I'm afraid that you can't receive 3 bytes correctly after 3 bytes had been transfered, as the SPI module doesn't have enough space or butter to storage the received bytes.

Hope it helps,
Have a great day,

Ping

-----------------------------------------------------------------------------------------------------------------------
Note: If this post answers your question, please click the Correct Answer button. Thank you!
-----------------------------------------------------------------------------------------------------------------------

0 Kudos

3,031 Views
lucasmahieu
Contributor III

Rely thanks jeremy,

in fact the camera that I want to communicate with via SPI is sending 3 commande Bytes in the same time I send it 3 Bytes

but only the first commande byte is important (the 2nd and 3rd have to be 0000...0)

and only the (2nd and 3rd Bytes of the receive Bytes are used full).

Do you have an idea of how a can do ? RT.png

0 Kudos