How to setup mbed to use SPI at 10MHz

16 Jun 2013

Hi,

Currently I have my mbed connected to an energy measurement chip ADE7758 that uses SPI to communicate the energy data, but the problem is that this chip uses a clock oscillator of 10MHz and mbed is using only 4MHz. I tried to change the spi.frequency on the mbed to 10MHz but the energy chip doesn't receive the full data as I could verify on the oscilloscope.

How I can change the mbed internal oscillator do start using 10MHz on the SPI communication?

Here is the code that I'm using:

#include "mbed.h"

SPI spi(p5, p6, p7); // mosi, miso, sclk
DigitalOut cs(p8);

uint8_t packet[9];
Serial pc(USBTX, USBRX);


/* Configuração MBED*/
DigitalOut led1(LED1);
DigitalOut led2(LED2); 
DigitalOut led3(LED3);
DigitalOut led4(LED4);


// **************************************
//     register name address length 
// **************************************
//read only register
#define REACTIVE_A 0x01 //16 Watt-Hour Accumulation Register for Phase A
#define REACTIVE_B 0x02 //16 Watt-Hour Accumulation Register for Phase B
#define REACTIVE_C 0x03 //16 Watt-Hour Accumulation Register for Phase C

#define AVARHR 0x04 //16 Var-Hour accumulation register for phase A 
#define BVARHR 0x05 //16 Var-Hour accumulation register for phase b 
#define CVARHR 0x06 //16 Var-Hour accumulation register for phase c 

Timer timeout;
bool timed_out;

int main() {
    uint8_t status_byte = 0x00;
    timeout.start(); //start the timeout timer
    
 
            
    
    while (1) {
        //try the 4 available modes to see if it will work
   
   for(int mode = 0; mode < 3; mode++) {
            spi.format(8, mode);
            spi.frequency(10000000); // 10MHz on sck
            cs = 0;
            led1 = 1;

            printf("Testing Command in SPI Mode %d\r\n", mode);
                spi.write(0x17); //send command byte
                
                
                wait(0.01);

            timeout.reset(); //reset the timeout to wait for reply for 2 seconds
            timed_out = false;
            
            //wait for the status byte
            while (status_byte == 0x00) {
                status_byte = spi.write(0x00);
                
                wait(0.01);
                
                //waited too long timeout
                if (timeout.read_ms() > 1000) {
                    timed_out = true;
                    break;
                }
            }

            if (!timed_out) {
                packet[0] = status_byte;
                //have the status (should check it really)

                //get the rest of the packet
                for (int i=1; i<5; i++) {
                    packet[i] = spi.write(0x00);
                }
                
                //output the packet
                for (int i=0; i<5; i++) {
                    printf("%02X ", packet[i]); //output the bytes in hex format on one line
                }
                printf("\r\n");
            } else {
                printf("Command timeout..\r\n");
            }

            cs = 1; // must raise cs between commands but after the reply
            led1 = 0; 
            wait(0.5);
        }
    }
}
16 Jun 2013

Just setting it on 10MHz should work, I have used it up to 48MHz (LPC1768). Well it can't reach exactly 10MHz with the available dividers, but close enough.

However more important, SPI sends a clock signal. It doesn't need to be synced somehow to that 10MHz clock it uses internally, So it should work fine at lower frequencies also.

16 Jun 2013

I just set the spi.frequency(10000000) at 10MHZ, but I've got this problem: sometimes it shows the values and other times it shows me 0xFF. What could be the error?

16 Jun 2013

10MHz is the absolute maximum you are allowed to use with that chip. I assume it is connected with fairly short wires? Also you might break some of the other timing demands of the chip if no additional delay is added at that speed. Do you really need to have it run at 10MHz?

16 Jun 2013

I have a distance of 6cm between mbed and the energy measurement chip. It's soldered in a PCB. I'm making right now a new design to test with a distance of only 1cm.

The accepted values for the SPI communication at ADE7758 need to be between 5MHZ and 15MHZ, as you can see at page 5 of the ADE7758 datasheet available at http://www.analog.com/static/imported-files/data_sheets/ADE7758.pdf .

I'm testing in this PCB the code below and I only start to get the right values after 50 reads. If I updated the mbed file to read a new register, it gives the right value but if I turn the mbed off and 15 minutes start the mbed again, it gives me 0xFF. After 50 reads or more it gives again the right value.

  1. include "mbed.h"

SPI spi(p5, p6, p7); mosi, miso, sclk DigitalOut cs(p8);

uint8_t packet[9]; Serial pc(USBTX, USBRX);

/* Configuração MBED*/ DigitalOut led1(LED1); DigitalOut led2(LED2); DigitalOut led3(LED3); DigitalOut led4(LED4);

******** register name address length ******** read only register

  1. define REACTIVE_A 0x01 16 Watt-Hour Accumulation Register for Phase A
  2. define REACTIVE_B 0x02 16 Watt-Hour Accumulation Register for Phase B
  3. define REACTIVE_C 0x03 16 Watt-Hour Accumulation Register for Phase C
  1. define AVARHR 0x04 16 Var-Hour accumulation register for phase A
  2. define BVARHR 0x05 16 Var-Hour accumulation register for phase b
  3. define CVARHR 0x06 16 Var-Hour accumulation register for phase c

Timer timeout; bool timed_out;

int main() { uint8_t status_byte = 0x00; timeout.start(); start the timeout timer

while (1) { try the 4 available modes to see if it will work

for(int mode = 0; mode < 3; mode++) { spi.format(8, mode); spi.frequency(10000000); 10MHz on sck cs = 0; led1 = 1;

printf("Testing Command in SPI Mode %d\r\n", mode); spi.write(0x17); send command byte

wait(0.01);

timeout.reset(); reset the timeout to wait for reply for 2 seconds timed_out = false;

wait for the status byte while (status_byte == 0x00) { status_byte = spi.write(0x00);

wait(0.01);

waited too long timeout if (timeout.read_ms() > 1000) { timed_out = true; break; } }

if (!timed_out) { packet[0] = status_byte; have the status (should check it really)

get the rest of the packet for (int i=1; i<5; i++) { packet[i] = spi.write(0x00); }

output the packet for (int i=0; i<5; i++) { printf("%02X ", packet[i]); output the bytes in hex format on one line } printf("\r\n"); } else { printf("Command timeout..\r\n"); }

cs = 1; must raise cs between commands but after the reply led1 = 0; wait(0.5); } } }

Regards

16 Jun 2013

It is the system clock that needs to be between 5MHz and 15Mhz, not the SPI clock! That is completely seperate from each other. Which immediatly makes me wonder how you wired the system. SPI should go to CS, SCLK, DIN and DOUT. On CLKIN it needs to get the 10MHz clock signal.

16 Jun 2013

I followed the test circuit for integrator off that is presented in the ADE7758 datasheet (http://www.analog.com/static/imported-files/data_sheets/ADE7758.pdf) on page 17.

16 Jun 2013

So with a 10MHz crystal? That is what they mean by a 5 to 15MHz clock signal. It is not related to the SPI clock speed.

16 Jun 2013

Yes, I used the 10MHz crystal

19 Jun 2013

Hi Erik,

After making a new PCB with the chip ADE7758 less than 1cm closer to mbed, now I'm getting the values that I should get.

Now I'm using the SPI frequency at 1MHZ but sometimes I can't get the real value or it shows me a different value. Maybe 1MHZ is too high for the new configuration as I'm losing values.

Regards

19 Jun 2013

I just see you just scan though all SPI modes. Then you get a wrong value if you use a wrong mode (can also result in a quite random error). Page 7 has an SPI timing diagram. SCLK is idle low, and data changes are on rising edge, so stable at falling edge.

That means CPOL = 0 (idle low), CPHA = 1 (capture on falling edge for CPOL = 0). Which means you need to use SPI mode 1. Your SPI frequency shouldn't be a problem, since it is rated up to 10MHz. (A bit lower means you have less chance on timing issues).