Go Down

Topic: How to set SPI clock to 76.9kHz by using the UNO R3? (Read 4 times) previous topic - next topic

jenaflex

I am coding a SPI device that required 13us clock period(76923Hz) . I calculate the clock divider is 208, but 208 is not available in the "SPI.setClockDivider()" function. How can I get the clock frequency I need?

Coding Badly


Seriously?  You have a device that requires that exact timing / frequency?

Graynomad

SPI is supposed to be bit-rate independent, what device do you have that needs such a specific rate?

______
Rob
Rob Gray aka the GRAYnomad www.robgray.com

jenaflex



Seriously?  You have a device that requires that exact timing / frequency?


it's a non-standard spi device(like spi, but not). I read the communication between the master device and slave device. The clock is 76.9kHz, 8 bits, idle high, rising edge sampling.

Tom Carpenter

#4
Jun 23, 2012, 11:20 pm Last Edit: Jun 23, 2012, 11:23 pm by TCWORLD Reason: 1
Have you got a link to the datasheet?

It won't be possible to be that specific with the SPI of the Arduino unless you use a different crystal frequency (and hence modified bootloader).

It may however be possible to do it using an Timer1 or Timer2 and compare/overflow interrupts. If you can post a datasheet I can give you a better example of how the timer could be used.
~Tom~

jenaflex

#5
Jun 24, 2012, 12:07 am Last Edit: Jun 24, 2012, 12:09 am by jenaflex Reason: 1

Have you got a link to the datasheet?

It won't be possible to be that specific with the SPI of the Arduino unless you use a different crystal frequency (and hence modified bootloader).

It may however be possible to do it using an Timer1 or Timer2 and compare/overflow interrupts. If you can post a datasheet I can give you a better example of how the timer could be used.


I am decoding a spi-like protocol. There are a master device and a slave device. Then I want use my UNO instead of the origin master device.

Waveform as follow picture.


As you can see the clock period is around 13 us. The corresponding clock frequency is 76.9kHz.

Is that possible to write my own clock generator that is based on the system clock and a clock counter? For example, count 100 system clock and set my_clk_generator to 1, then count another 100 system clock and set  my_clk_generator to 0.

Graynomad

OK so you're not generating this you're at the mercy of an existing system.

Why not just hang your Arduino off the same line as a slave, that would allow you the sample one signal in hardware.

Alternatively run the CLK signal to an external interrupt input, then read the two signals in the ISR and reconstruct the data from that.

Either way you don't have to know or care about the frequency.

______
Rob
Rob Gray aka the GRAYnomad www.robgray.com

Tom Carpenter

What I would suggest you do is to use the SPI module, set the divider to 128 (that will give you 125kHz), and try it.

In all likelyhood the slave device will work fine at that frequency. The design of the SPI devices should allow them to run at any speed the master sets (as long as they can keep up). I would think that the slave should manage 125kHz.
~Tom~

Graynomad

Quote
Then I want use my UNO instead of the origin master device.

Doh, I didn't read this bit.

Just because you are seeing 76.9kHz now that doesn't mean you have to generate the same, that frequency is probably generated by some bit banging from the current master device using who-knows-what processor, language and crystal.

If the slave device didn't work at 125kHz as TCWORLD said or some other slow rate I would eat my Arduino (the small one that is :)).

______
Rob
Rob Gray aka the GRAYnomad www.robgray.com

jenaflex


What I would suggest you do is to use the SPI module, set the divider to 128 (that will give you 125kHz), and try it.

In all likelyhood the slave device will work fine at that frequency. The design of the SPI devices should allow them to run at any speed the master sets (as long as they can keep up). I would think that the slave should manage 125kHz.


It seems that it doesn't work.



My Code

Code: [Select]

#include "Arduino.h"
//include the SPI library
#include <SPI.h>

const int CLKpin = 13; // set pin 13 as the CLK
const int MOSIpin = 11; // set pin 11 as the MOSI
const int MISOpin = 12; // set pin 12 as the MISO
const int SSpin = 10; // set pin 10 as the SS

// initialize setup
void setup(){
 pinMode (CLKpin, OUTPUT); // set CLKpin as an output
 pinMode (MOSIpin, OUTPUT); // set MOSIpin as an output
 pinMode (MISOpin, INPUT); // set MISOpin as an input
 pinMode (SSpin, OUTPUT); // set SSpin as an output
 SPI.begin(); // initialize SPI
 
 SPI.setBitOrder(MSBFIRST);
 SPI.setDataMode(SPI_MODE3);
 SPI.setClockDivider(SPI_CLOCK_DIV128);
}



void loop() {
 byte COMMAND = 0x13;
 byte cmd_step = 0x02;
 
 SPI.transfer(COMMAND); // contract iris command
 delayMicroseconds(191);
 
 SPI.transfer(cmd_step);
 delayMicroseconds(16000);

Graynomad

It does indeed look like the slave is struggling, can you further reduce the speed?

Do you have a data sheet for the device?

______
Rob
Rob Gray aka the GRAYnomad www.robgray.com

Tom Carpenter

#11
Jun 25, 2012, 05:13 pm Last Edit: Jun 25, 2012, 05:24 pm by TCWORLD Reason: 1
Just as a quick test, try adding this to the start of the setup():


 CLKPR = 0b10000000;
 CLKPR = 0b00000001;


You will also have to half all of the delays for this test as the Arduino IDE wont know how to account for this change.

What it does is prescales the whole system clock from 16MHz down to 8MHz, which will mean you get a 62.5kHz SPI clock.



The other thing is what are the three signals in the first scope trace you posted? It doesn't quite look like SPI.
~Tom~

jenaflex


It does indeed look like the slave is struggling, can you further reduce the speed?

Do you have a data sheet for the device?

______
Rob


I haven't the data sheet. I use the "SPI.setClockDivider(SPI_CLOCK_DIV128); " , which is the slowest spi clock in the SPI library.

I am decoding the protocol of Canon lens. There is no data sheet available. But there is a Canon services manual that was released by some guys.

The Canon services manual said as follows:
clock pulse 62.5kHz, 16us pulse
8 bit

My observation on oscilloscope:
clock pulse,13us pulse
8bit
clock idle high
rising edge sampling


Other non-official info (might be wrong):
1. Motorola SPI; 8 bit serial; Such as the protocol used with the 68HC05 chip.

Tom Carpenter

Oh, another option if you dont need the serial port is to use it in fake SPI mode. This allows you exact control over the baud rate.

Example (Note: This is untested, I based it on the code examples in the 328p datasheet):

Code: [Select]
void SPIInitialise() {
 // put your setup code here, to run once:
 pinMode(4,OUTPUT); //SCLK pin
 pinMode(0,INPUT); //MISO
 pinMode(1,OUTPUT); //MOSI
 pinMode(2,OUTPUT); //SS
 
 //Set UART as SPI.
 UBRR0 = 0;
 UCSR0C = (1<<UMSEL01)|(1<<UMSEL00)|(1<<UCPHA0)|(1<<UCPOL0);  //Set to MasterSPI (UMSEL0=1, UMSEL1=1), in Mode3 (CPHA=1, CPOL=1)
 UCSR0B = (1<<RXEN0)|(1<<TXEN0); //Enable TX and RX (TX = MOSI, RX = MISO)
 
 UBRR0 = 127; //SPI clock rate. UBRR0 = (FCPU/(2*BAUD)) -1;. So for 62.5KHz, UBRR0 = (16000000/(2*62500))-1 = 128 -1 = 127
}

byte SPITransfer(byte data) {
 
 /* Wait for empty transmit buffer */
 while ( !( UCSR0A & (1<<UDRE0)) );
 
 /* Put data into buffer, sends the data */
 UDR0 = data;
 
 /* Wait for data to be received */
 while ( !(UCSR0A & (1<<RXC0)) );
 
 /* Get and return received data from buffer */
 return UDR0;
}

void setup(){
 SPIInitialise();
}

void loop(){
 //Main loop
}
~Tom~

Nick Gammon

My bit-banged SPI used for uploading hex files:

Code: [Select]
// bit banged SPI pins
const byte MSPIM_SCK = 4;  // port D bit 4
const byte MSPIM_SS  = 5;  // port D bit 5
const byte BB_MISO   = 6;  // port D bit 6
const byte BB_MOSI   = 7;  // port D bit 7

// 8 MHz clock on this pin
const byte CLOCKOUT = 9;


// for fast port access (Atmega328)
#define BB_MISO_PORT PIND
#define BB_MOSI_PORT PORTD
#define BB_SCK_PORT PORTD
const byte BB_SCK_BIT = 4;
const byte BB_MISO_BIT = 6;
const byte BB_MOSI_BIT = 7;

// control speed of programming
const byte BB_DELAY_MICROSECONDS = 4;

...


// Bit Banged SPI transfer
byte BB_SPITransfer (byte c)
{       
  byte bit;
   
  for (bit = 0; bit < 8; bit++)
    {
    // write MOSI on falling edge of previous clock
    if (c & 0x80)
        BB_MOSI_PORT |= _BV (BB_MOSI_BIT);
    else
        BB_MOSI_PORT &= ~_BV (BB_MOSI_BIT);
    c <<= 1;

    // read MISO
    c |= (BB_MISO_PORT & _BV (BB_MISO_BIT)) != 0;

   // clock high
    BB_SCK_PORT |= _BV (BB_SCK_BIT);

    // delay between rise and fall of clock
    delayMicroseconds (BB_DELAY_MICROSECONDS);

    // clock low
    BB_SCK_PORT &= ~_BV (BB_SCK_BIT);
    }
   
  return c;
  }  // end of BB_SPITransfer


By tweaking BB_DELAY_MICROSECONDS you should be able to get the frequency you want.
http://www.gammon.com.au/electronics

Go Up