Pages: [1] 2 3   Go Down
Author Topic: How to set SPI clock to 76.9kHz by using the UNO R3?  (Read 4075 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
Newbie
*
Karma: 0
Posts: 28
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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?
Logged

Global Moderator
Dallas
Offline Offline
Shannon Member
*****
Karma: 210
Posts: 13036
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset


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

nr Bundaberg, Australia
Offline Offline
Tesla Member
***
Karma: 129
Posts: 8601
Scattered showers my arse -- Noah, 2348BC.
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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

______
Rob
Logged

Rob Gray aka the GRAYnomad www.robgray.com

Offline Offline
Newbie
*
Karma: 0
Posts: 28
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset


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.
Logged

Leeds, UK
Offline Offline
Edison Member
*
Karma: 80
Posts: 1729
Once the magic blue smoke is released, it won't go back in!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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.
« Last Edit: June 23, 2012, 04:23:33 pm by TCWORLD » Logged

~Tom~

Offline Offline
Newbie
*
Karma: 0
Posts: 28
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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.


* Post to Forum_1.JPG (114.39 KB, 1024x768 - viewed 127 times.)
« Last Edit: June 23, 2012, 05:09:48 pm by jenaflex » Logged

nr Bundaberg, Australia
Offline Offline
Tesla Member
***
Karma: 129
Posts: 8601
Scattered showers my arse -- Noah, 2348BC.
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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
Logged

Rob Gray aka the GRAYnomad www.robgray.com

Leeds, UK
Offline Offline
Edison Member
*
Karma: 80
Posts: 1729
Once the magic blue smoke is released, it won't go back in!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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.
Logged

~Tom~

nr Bundaberg, Australia
Offline Offline
Tesla Member
***
Karma: 129
Posts: 8601
Scattered showers my arse -- Noah, 2348BC.
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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 smiley).

______
Rob
Logged

Rob Gray aka the GRAYnomad www.robgray.com

Offline Offline
Newbie
*
Karma: 0
Posts: 28
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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:
#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);


* Post to Forum_2.JPG (119.54 KB, 1024x768 - viewed 122 times.)
Logged

nr Bundaberg, Australia
Offline Offline
Tesla Member
***
Karma: 129
Posts: 8601
Scattered showers my arse -- Noah, 2348BC.
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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
Logged

Rob Gray aka the GRAYnomad www.robgray.com

Leeds, UK
Offline Offline
Edison Member
*
Karma: 80
Posts: 1729
Once the magic blue smoke is released, it won't go back in!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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.
« Last Edit: June 25, 2012, 10:24:30 am by TCWORLD » Logged

~Tom~

Offline Offline
Newbie
*
Karma: 0
Posts: 28
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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.
 
Logged

Leeds, UK
Offline Offline
Edison Member
*
Karma: 80
Posts: 1729
Once the magic blue smoke is released, it won't go back in!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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:
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
}
Logged

~Tom~

Global Moderator
Offline Offline
Brattain Member
*****
Karma: 503
Posts: 19086
Lua rocks!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

My bit-banged SPI used for uploading hex files:

Code:
// 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.
Logged


Pages: [1] 2 3   Go Up
Jump to: