SPI newbie questions part II

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

SPI newbie questions part II

1,058 Views
Cram
Contributor III

Hi all,

 

we cam from: https://community.freescale.com/message/63224#63224

 

I understand that I have something worng in my code, I read a lot of documentation and look for some examples but I don't find a solution, my problem know is that I receive teh data from the sensor in reversebit mode (1=low and 0=high).

 

I configured the SPI modulo as:

  // SPI
  SPIC1_SPE=1;
  SPIC1_SPIE=0;//1
  SPIC1_MSTR=1;
  SPIC1_CPHA=0;
  SPIC1_SSOE=1;
  SPIC1_CPOL=1;
  SPIC1_LSBFE=0;
 
  //SPIC2
  SPIC2_MODFEN=0;
  SPIC2_BIDIROE=0;
 
 
  //SPIBR SPI clock = BUSCLK/4 = 1MHz
  SPIBR_SPPR2=1;
  SPIBR_SPR1=1;

 

then a GPIO as a SS, and make a loop as:

 


            STROBE=0;
            
            for (vegades=0;vegades<2;vegades++){   
                   
                   while (SPIS_SPTEF==0) clrWD();
                   
                   SPID=counter;   
                 
                   while (SPIS_SPRF==0) clrWD();
                   
                   res[vegades] = SPID;
              
                   counter=26;   //dummy
                                
                   
            }
            STROBE=1;

 

SO in that way I recevie 2 byte with the 10 bit angular position and 6 bits with the sensor status and all is ok.

 

But now I checking the sensor behavior: the data output  with the PWM sensor output and when the PWM output is like 26 I receive 998, I didn't realize of that the first time because I didn't need to compare both signals, and also I'm not able to localize the status bits (where are they and the logic levels don't match with the reality).

 

So i'm doing something wrong?

Labels (1)
0 Kudos
5 Replies

442 Views
bigmac
Specialist III

Hello,

 

I notice that the code within the file main.c differs from the posted code snippet in that the STROBE signal is becoming inactive after each byte received.  The STROBE line should remain low for the duration of the 16-bit transfer, as shown in the snippet.

 

I notice that you have also defined DATA as the pin corresponding to MOSI.  While this may be a spurious macro definition, I presume that the actual connection between the encoder and the MCU is DO -> MISO (PTBD4)?

 

The following line seems to contain an error:

resL = ReceivedByteH & 0x70;

 

I would suspect that the mask value should be 0xE0.  i also think that there is a related problem where you combine the two bytes into a single word value,

resultat = (resH * + (resL / 16);

 

It would seem that the division should be by 32 to achieve a value of 0 to 7.  Maybe I would tend to use the following alternative expression, as a personal choice:

resultat = (resH << 3) + (resL >> 5);

 

With your SPI initialisation, you are separately initialising individual bits within the same register.  In addition to creating inefficient code, it may lead to additional sequencing problems.  The best approach is to simultaneously initialise all bits in the registers, for example:

SPIC1 = 0x58;

SPIC2 = 0x00;

 

Additional documentation on the details of the setup should be included as comments.  Your SPI clock rate seems to be bus clock /8, rather than the intended bus clock /4.

 

Some more general comments about your coding:

  • I notice that you are using global variables in many instances where local variables would suffice.
  • Since your intent is a 1 MHz SPI clock, the wait loop for either SPI flag to become set will be no more than a few microseconds - a COP timer reset within each loop is quite superflous.  In fact probabably better to have a COP timeout reset should there be an abnormal delay; i.e hardware latch up.
  • With the need to handle only two SPI bytes for each reading, using a for-loop makes the code more complex than it needs to be.  The code might also be incorporated into a function that returns the required word value.

 

word get_pos( void){  word resH, resL;  STROBE = 0;  while (!SPIS_SPTEF);  SPID = 0;            // Send dummy byte  while (!SPIS_SPRF);  // Wait for completion of send  resH = SPID & 0x007F;  SPID = 0;            // Send next dummy byte  while (!SPIS_SPRF);  // Wait for completion of send  resL = SPID & 0x00E0;                 STROBE = 1;  return ((resH << 3) + (resL >> 5));}

 

for (i = 0; i < arrayPos; i++)              bufferRead[i] = get_pos();

Regards,

Mac

 

0 Kudos

442 Views
Cram
Contributor III

Hi bigmac

 

 

I notice that the code within the file main.c differs from the posted code snippet in that the STROBE signal is becoming inactive after each byte received.  The STROBE line should remain low for the duration of the 16-bit transfer, as shown in the snippet.

 Yes thats true it's just a problem of save as ... sorry for the mistake.

 

 

I notice that you have also defined DATA as the pin corresponding to MOSI.  While this may be a spurious macro definition, I presume that the actual connection between the encoder and the MCU is DO -> MISO (PTBD4)?

 

 

Yes it is.

 

 

The following line seems to contain an error:resL = ReceivedByteH & 0x70;

 

 

Yes it should be ReceivedByteL, anyway I will test all of your porpousal, seems to be more easy to manage it.

 

I tested the code that you wrote to me (thxs) but I still having the same problem (maybe I need to read more carefully the encoder doc) when I spected to receive 1000 I received the 24 (the complementary data), and I'm not able to localize the satuts bit, I will explain it with an example:

 

Iamgine that the magnet over the enconder is in the 90º (256) (359º equals 1024), I can adjust the position using the PWM output from the encoder, so the data transmit should be:

 

  D9 D8 D7 D6 D5 D4 D3 D2 D1 D0 OCF COF LIN MIN MDEC EPAR

  0     0    1    1    1    1    1    1    1   1     0        ?      ?     0         0        ?

 

I'm searching for the angular position and for the COF bit or MIN + MDEC, but I can decode 270º(768):

 

  D9 D8 D7 D6 D5 D4 D3 D2 D1 D0 OCF COF LIN MIN MDEC EPAR

  0     1    1   0    0    0    0    0    0   0     0        ?      ?     1         1        ?

 

thta's my problem, I supossed thta I'm doing something worng, and then I started to make samll changes with no result.

 

thxs for all

 

Cram

 

0 Kudos

442 Views
bigmac
Specialist III

Hello Cram,

 

The status bits were masked out within the get_pos() function.  If you need to monitor these, perhaps this function should simply return the raw 16-bit data.

 

word get_pos( void){  word result;  STROBE = 0;  while (!SPIS_SPTEF);  SPID = 0;            // Send dummy byte  while (!SPIS_SPRF);  // Wait for completion of send  result = (SPID & 0x007F) << 8;  SPID = 0;            // Send next dummy byte  while (!SPIS_SPRF);  // Wait for completion of send  result += SPID;      // Includes status bits        STROBE = 1;  return result;}

 

#define ERRMASK  0x0C  // COF and LIN error bitsword val;byte status;val = get_pos();status = (byte)(val & 0x001F)...
if ((status & ERRMASK) == 0) {  bufferRead[i] = val >> 5;   // Right align 10-bit position value
...}
else {

// Reading error action

}

 How do you know that your reference rotational position is 90 degrees, rather than 270 degrees?  If you are comparing the absolute result with the PWM waveform, is it possible that your measurement of the PWM pulse period may be incorrect, perhaps by starting with the wrong edge?  This is likely to be so if the absolute reading increases with clockwise rotation, but the measured pulse period decreases.

 

Regards,

Mac

 

0 Kudos

442 Views
Cram
Contributor III

 

 How do you know that your reference rotational position is 90 degrees, rather than 270 degrees?  If you are comparing the absolute result with the PWM waveform, is it possible that your measurement of the PWM pulse period may be incorrect, perhaps by starting with the wrong edge?  This is likely to be so if the absolute reading increases with clockwise rotation, but the measured pulse period decreases.

 

 

I checked it (rotational reference) with and oscilloscope and the PWM output from the encoder without data adquisition. So when I saw a PWM signal I receive the complementary data from the encoder (ok I can something like result=1024-getpos(); and then I have the same position, but it's not logical to have a PWM output and the complementary for the SPI).

 

So my doubt is if I was setting up the modulo in the wrong sense and I misunderstood the logical level 0 and 1.  And when I need to check if the recevied byte is valid or invalid I must check the COF (0= valida data and 1=invalid data) but now for me is in the revers emode, So I need to validate the behavior, I will ask to the supplier in order to assure the measure.

 

Thxs for all.

Cram

 

I will test you mask proposal, it's more or less like mine but anyway I'll test it.

0 Kudos

442 Views
bigmac
Specialist III

Hello Cram,

 

Another test that you might try is to slowly rotate the magnet unil you get the index output pulse, and then check the corresponding absolute reading and PWM duty cycle.  You might also check whether the absolute reading and the PWM output increases or decreases as the magnet is turned clockwise.

 

The expression to get the ones complement of a 10-bit value should actually be -

result = 1023 - (getpos() >> 5);

 

Another alternative to this expression would be -

result = (getpos() >> 5) ^ 0x03FF;

 

For both of these expressions I have added the right shift required to eliminate the status bits.

 

Regards,

Mac

 

0 Kudos