Difficulty with SPI interface - MC9S08SG32

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

Difficulty with SPI interface - MC9S08SG32

Jump to solution
1,193 Views
kvkk
Contributor I

Hi there,

 

I am new to Freescale family. Currently I am  facing a problem with interfacing "Intersil HIP9011"(Knock Signal Processing chip) to MC9S08SG32 Microcontroller through SPI. I am using DEMO9S08SH32-SG32 demo board featuring MC9S08SG32 MCU for the purpose. I had gone through a lot of posts related to  SPI on this Forum but could not solve the issue. Finally ended up posting this.

 

Actually the HIP9011 chip is configured to perform its function by programming 5 configuration bytes through SPI by a microcontroller. In addition to the Chip/slave select (CS/SS) signal, the chip requires INT/HOLD signal also to be held low for programming (the datasheet is attached for reference). I am presently using MCU as the master and the chip as the slave.

 

The problem is, inspite of pulling the CS and INT/HOLD signal low and loading the SPID register with the data byte, I see no pulses/data on SCK and MOSI lines on the scope indicating there is no clock and hence no data is being transferred. Also the SPTEF flag always remains 1 inspite of loading the data and the SPRF flag goes high immediately indicating a byte shifted from the chip. I have confirmed all the hardware connections.

 

Request you guys to help me in figuring out what the problem is..

 

The code and the datasheet of the chip are attached for reference.

 

Thanks in Advance

Labels (1)
0 Kudos
Reply
1 Solution
488 Views
bigmac
Specialist III

Hello Kvkk,

 

The probable reason you encounter an infinite loop is that you are attempting to single step through the SPISendChar() function, whilst monitoring the state of the SPIS and SPID registers.  The debug process will therefore clear the SPRF flag before the loop test can occur.  The solution is to use a break point, rather than attempting to single step the function.

 

Even so, your code does not actually clear the SPRF flag - the datasheet should describe the mechanism required.

 

My take on your code might be as follows:

#define LED_ON    PTCD_PTCD1 = 0#define LED_OFF   PTCD_PTCD1 = 1#define CS_ON     PTCD_PTCD2 = 0#define CS_OFF    PTCD_PTCD2 = 1#define HOLD_MODE PTCD_PTCD3 = 0#define INT_MODE  PTCD_PTCD3 = 1void main(void){   word tmp;   MCU_init();               /* Device Initialization */   CS_OFF;                   /* SS Initial State */   INT_MODE;                 /* Set INTG Mode */   LED_OFF;                  /* Turoff LED */             HOLD_MODE;                /* Set HOLD mode */   (void)SPISend( Ox40);     /* Send Prescaler byte */   // LED2();     (void)SPISend( 0xE0);     /* Send Channel Select byte */   // LED2();   (void)SPISend( 0x2F);     /* Send BPF Center freq byte */   // LED2();   (void)SPISend( 0x8E);     /* Send Gain Control byte */   // LED2();   (void)SPISend( 0xD4);     /* Send Integrator Tc byte */   // LED2();      for (tmp = 0; tmp < 20; tmp++); // Wait 8us minimum   INT_MODE;                       /* Set INTG Mode */   LED2();       for ( ; ; ) {      __RESET_WATCHDOG();       } /* loop forever */}byte SPISend( byte data) {   CS_ON;     // Select slave device   while (!SPIS_SPTEF);    // Wait until ready to send   SPID = data;            // Send byte value   while (!SPIS_SPRF);     // Wait until transfer is complete   data = SPID;            // Also clears flag   CS_OFF;                 // Un-select slave device   return data; }void LED2( void){   word tmp;   LED_ON;   for (tmp = 0; tmp < 3500; tmp++);    LED_OFF;   for (tmp = 0; tmp < 3500; tmp++);}

 

Regards,

Mac

 

View solution in original post

0 Kudos
Reply
4 Replies
488 Views
bigmac
Specialist III

Hello, and welcome to the forum.

 

Firstly, the timing diagram for the slave device suggests that a setting of CPOL = 0 and CPHA = 1 is the required setting, i.e. the input data is read on the negative clock edge.

 

Now consider your following code:

 

void SPISendChar(unsigned char data)
{
   while (!SPIS_SPTEF && PTCD_PTCD3);  /* Wait until transmit buffer is empty */
   PTCD_PTCD2 = 0;                     /* Select slave */
   SPID = data;                        /* Start to send data */
   (void)(SPIS == 0);                  // clear flag
   PTCD_PTCD2 = 1;                     /* Un-select slave */ 
}
.
This would differ from other recent SPI posts on this forum.  Since you are not waiting for the SPRF flag to become set before raising the SS signal at PTCD2, SPI communications will be prematurely aborted at the slave.  After the flag becomes set, you will then need to clear the flag.  In the process of doing this, you may as well return the received byte value (via MISO), to provide a more general SPI function.

 

I would not include the test for PTCD3 set within the function, because if set, you would potentially enter an indefinite loop (subject to COP timeout).  Far better to make sure that PTCD3 is clear before calling the function.

 

The delay loop, after the sending of each byte, may then be eliminated.  However, after the final byte is sent, you will need a delay of at least 8 us before again raising PTCD3, the INT/HOLD signal.

 

Finally, I do not see the need for the curr_byte global variable.  For example, the following would be more efficient.

SPISendChar( 0x40);         /* Send Prescaler byte */

.

 

Regards,

Mac

 

0 Kudos
Reply
488 Views
kvkk
Contributor I

Hello bigmac

 

Firstly thank you for your prompt reply. I really appreciate it.

 

" Since you are not waiting for the SPRF flag to become set before raising the SS signal at PTCD2, SPI communications will be prematurely aborted at the slave.  After the flag becomes set, you will then need to clear the flag.  In the process of doing this, you may as well return the received byte value (via MISO), to provide a more general SPI function. "

 

Based on your suggestion atated above, I modified the code as 

 

void SPISendChar(unsigned char data)
{
   while (!SPIS_SPTEF && PTCD_PTCD3);  /* Wait until transmit buffer is empty */
   PTCD_PTCD2 = 0;                     /* Select slave */
   read = SPIS;                        /* read SPIS whe SPTEF = 1 to initiate a transfer */

   SPID = data;                        /* Start to send data */
   while (!SPIS_SPRF)                  /* wait till the byte is recieved */

   (void)(SPIS == 0);                  // clear flag
   PTCD_PTCD2 = 1;                     /* Un-select slave */ 
}

If I do this I think I am getting stuck in a infinite loop as the SPRF flag is reset on the instruction "While(!SPIS_SPF)" (Refer the attachment No:1).

 

So I tried to add a delay after writing to the SPID so that the data transfer is not prematurely aboted. It goes like this

 

void SPISendChar(unsigned char data)
{
   while (!SPIS_SPTEF && PTCD_PTCD3);  /* Wait until transmit buffer is empty */
   PTCD_PTCD2 = 0;                     /* Select slave */
   read = SPIS;                        /* read SPIS whe SPTEF = 1 to initiate a transfer */

   SPID = data;                        /* Start to send data */
   for (tmp=0;tmp<50;tmp++);           /* wait till the byte is recieved */

   (void)(SPIS == 0);                  // clear flag
   PTCD_PTCD2 = 1;                     /* Un-select slave */ 
}

 

Then I see that I am not stuck in a loop, but as usual there is no clock and no data on the MOSI pin (Refer the attachment No:2).

 

Any more suggestions please..

 

Regards

Kvkk

0 Kudos
Reply
489 Views
bigmac
Specialist III

Hello Kvkk,

 

The probable reason you encounter an infinite loop is that you are attempting to single step through the SPISendChar() function, whilst monitoring the state of the SPIS and SPID registers.  The debug process will therefore clear the SPRF flag before the loop test can occur.  The solution is to use a break point, rather than attempting to single step the function.

 

Even so, your code does not actually clear the SPRF flag - the datasheet should describe the mechanism required.

 

My take on your code might be as follows:

#define LED_ON    PTCD_PTCD1 = 0#define LED_OFF   PTCD_PTCD1 = 1#define CS_ON     PTCD_PTCD2 = 0#define CS_OFF    PTCD_PTCD2 = 1#define HOLD_MODE PTCD_PTCD3 = 0#define INT_MODE  PTCD_PTCD3 = 1void main(void){   word tmp;   MCU_init();               /* Device Initialization */   CS_OFF;                   /* SS Initial State */   INT_MODE;                 /* Set INTG Mode */   LED_OFF;                  /* Turoff LED */             HOLD_MODE;                /* Set HOLD mode */   (void)SPISend( Ox40);     /* Send Prescaler byte */   // LED2();     (void)SPISend( 0xE0);     /* Send Channel Select byte */   // LED2();   (void)SPISend( 0x2F);     /* Send BPF Center freq byte */   // LED2();   (void)SPISend( 0x8E);     /* Send Gain Control byte */   // LED2();   (void)SPISend( 0xD4);     /* Send Integrator Tc byte */   // LED2();      for (tmp = 0; tmp < 20; tmp++); // Wait 8us minimum   INT_MODE;                       /* Set INTG Mode */   LED2();       for ( ; ; ) {      __RESET_WATCHDOG();       } /* loop forever */}byte SPISend( byte data) {   CS_ON;     // Select slave device   while (!SPIS_SPTEF);    // Wait until ready to send   SPID = data;            // Send byte value   while (!SPIS_SPRF);     // Wait until transfer is complete   data = SPID;            // Also clears flag   CS_OFF;                 // Un-select slave device   return data; }void LED2( void){   word tmp;   LED_ON;   for (tmp = 0; tmp < 3500; tmp++);    LED_OFF;   for (tmp = 0; tmp < 3500; tmp++);}

 

Regards,

Mac

 

0 Kudos
Reply
488 Views
kvkk
Contributor I

Hello bigmac,

 

Modification in the code suggested by you works and the chip is on and running well. Sorry for the delay in replying back, I was busy on some other project and could not verify the code.

 

Thank you very much for your kindest help and invaluable guidance.

 

Regards

KVKK

0 Kudos
Reply