Timer, SSI-Interface

Hi all,

i'm trying to build a SSI-interace with the Arduino Board, i.e. one has a clock signal and synchorn to that signal one gets the data out of the device one is interfaceing.
The problem ist that the frequency of the Clock signal has to be above 100kHz, and during one tick one has to read the signal from a I/O-port.
After trying the "normal" Code, which means at last a "for Loop": - "togle the clock"- "read the port" - "togle the clock" and again....
seems not quick engouh.
Then i started to look at Forums, for the inbuild timer routine and code samples, finding this
http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1143470863/4
unluckiely the mantioned snipped is not compileable becaus of the missing function "timerAttach" which is located in "timer.h". Including this header results in another error ("avrlibtypes.h: 70: error: expected unqualified-id before numeric constant"; which has some thing in common with typedefs...).....

So what I like to know is if it is possible to realise an Interface described above, with the usage of inbuild timers?
Or is the arduino Board not quick enough for this kind of task?

Thanks

Stephan

I guess what you're trying to build is an SPI interface.

have you looked at the example for the Qt401? http://www.arduino.cc/en/Tutorial/Qt401
there is an SPI routine written in the arduino language that has been working quite well.

otherwise you need to look into "Hardware SPI"

here is some c code from Peter Fleury that uses the SPI master built-in the atmega8

#define SPI_CHIP_SELECT PB2             // SS pin is used here, but any pin can be used
#define SPI_MOSI        PB3             // SPI MOSI pin 
#define SPI_SCK         PB5             // SPI SCK pin
#define SPI_DDR         DDRB            // port used by SPI

int main(void)
{
    uint8_t led = 2;

    /* SPI port initialization (/SS, MOSI, SCK output, MISO input) */
    SPI_DDR  = _BV(SPI_CHIP_SELECT) + _BV(SPI_MOSI) + _BV(SPI_SCK);

    /* SPI interrupt disabled, SPI port enabled, master mode, MSB first, SPI mode 3, SPI Clock = XTAL/4 */
    SPCR = _BV(SPE) +_BV(MSTR) + _BV(CPOL) + _BV(CPHA);

    for(;;)
    {
        PORTB &= ~_BV(SPI_CHIP_SELECT);     // enable SPI device
        SPDR = led;                         // send data to SPI device (turn LED on/off)
        while (!(SPSR & _BV(SPIF)));        // wait until write complets
        PORTB |= _BV(SPI_CHIP_SELECT);      // disable SPI device

        led ^= 2;                           // toggle LED

        delay(65535);                       // delay 0.1 seconds
   }

}

consider that the clock used by this code will be in the region of 4 MHZ (the code mentions clock/4...)

let me know if this works for you

Thanks for this fast reply,

luckily i'm really trying to make an SSI-Interface (which means Serial Synchron Interface), which is much simpler than an SPI one. I don't have to pass an address to the device, just toggle the clock and get the (synchron comming) output.
I guess i have to make my homework now and digg me thru to code, to get the relevant parts.....

I gonna let you know

Thanks again

Stephan

Hallo again,

finaly i got it working. Give me a few days to clean up my code. I'll then post it here.

To describe the project: The SSI is needed to get the absolute position of an rotary absolute enconder, then transfere the Position to MAX/MSP/Jitter, and play a video synchron to the read Position of the encoder.
Right now i'm only hassling with the HF-electronics, but in principle it works right now.

Thanks a lot,

Stephan

hi Stephan,

what kind of rotary encoder do you use? i need to read the position of a hand crank.

best, kuk
(actually Stephan too :slight_smile:

Hi Kuk,
its form Kübler GmbH and its a rotary absolute multiturn encoder 5862 series, see www.kuebler.com for details. Its not cheap but its relieable industial optical encoder.
You don't have to take this one because the SSI is used as an industrial standart, so have a look at other companies for the best encoder that fits your needs.

stephan

Finally,

here is the code, i promised weeks ago.....

/*
SSI (Serial Synchron Interface) for the Kübler GmbH rotary absolute multiturn encoder 5862 series, see www.kuebler.com. 
Hardware specifications: 
* 25-bit rotary absolute multiturn encoder
* Interface: SSI (with RS485 line definitions)
* encoded as: Gray-Code

* SSI:
  - SSI-Clock TicTac must be equal or less 10µs. 
  - 26 Clock TicTac are needed for the whole Position consiting of a 25 Bit word, the first TicTac is needed for he status bit, which enconde the status of the device, (0) for not clear. 
  - After the the 26 TicTacs a puse of max. 80µs is needed for a new Position to be available.

* This Program:
  - emulates a SSI with the Arduino Ports 12 (clock) and 11 (data).
  - transform the gray encoded Position to binary encoded Position
  - send the Position to Max/MSP/Jitter via USB
  
* Electronics needed:
  - 2 RS485 line drivers (e.g. sn75176) are needed, if you want to save ports and clean up the ignals.
  - for the start-sequence and the reset a uln 2803 could used (not implemented yet).
  - a few resitors for cleaning the singnals.... 
*/


/*
Variables
*/
byte getByte;         //dummy Byte for serialAvailable 
byte grayArray[26];   //Array reseved for the recieved Gray Code
byte binaryArray[26]; //Array reserved for the binary transformed Code
byte dummy;           //dummy
int i = 0;            //loop counter
int j = 0;            //loop counter

/*
functionprototypes
*/
void getPosition();               // saves the status bit and the 25 position bits in the grayArray, read from the register as PINB. The only time-critical process.
void condensePosition();          // condenses the recieved Byte (PINB) in grayArray to the only intersting bit (PB3) in PINB.
void transformPosition();         // transforms the 25 postion bits to binary and saves them in binaryArray
void sendPosition();              // sends the binarayArray - enclosed in '255' - via USB to Max/MSP/Jitter
//void resetRoutine();            // external Reset of the encoder, to select rotary direction and define zero Position.

/*
setup
*/
void setup()
{
  DDRB = (1<<PB4); //PB4 is digital pin No 12
  delay(500); 
  beginSerial(38400);  
}

/*
Main
*/
void loop()
{
  if(PINB & (1<<PB3))
  {
  getPosition();  
  }
             // delay for device to become ready again 
  if(Serial.available())            // check if a request form max is there. To avoid a buffer overrun, MAX/MSP/Jitter is playing PingPong with the arduino Board, if max send any via sierial, arduino responds with the newest Position
  {
    while(Serial.available() > 0)   // reads all the data send to the arduino board
    {
      dummy = Serial.read();
    }                               // and finaly sends the Position
    condensePosition();
    transformPosition();
    sendPosition();
  }
  delay(2);
}


/*
function definitions
*/

void getPosition()
{
  for(j = 0;j < 26; j++)          // Untested yet
  {
     grayArray[j] = 0;
     binaryArray[j] = 0; 
  }

  delayMicroseconds(40);
  
  for(j = 0;j < 26; j++)
  {
    PORTB = (0<<PB4);
    delayMicroseconds(3);
    grayArray[j]= PINB;  //delayMicroseconds(3) fits a 10us tictac
    PORTB = (1<<PB4);
    delayMicroseconds(3);   
  }
  
  delayMicroseconds(100);
  
}

void condensePosition()
{
    for(i = 0;i < 26; i++)
    {
      if(grayArray[i] & (1<<PB3))
      {
        grayArray[i] = 1;
      }
      
      else
      {
        grayArray[i] = 0;
      }
    }
}

void transformPosition()
{
    binaryArray[0]= grayArray[0];                          // transfer status bit
    binaryArray[1] = grayArray[1];                         // gray to binary, transfer the MSB
    for(i = 2; i < 26; i++)                                // all other bits are transformed according to: binaryArray[i] = XOR(grayArray[i], binaryArray[i - 1]), cf. http://www.faqs.org/faqs/ai-faq/genetic/part6/section-1.html
    {
      binaryArray[i]= grayArray[i] ^ binaryArray[i - 1]; 
    } 
}

void sendPosition()                                        //This function just sends the raw data (not packed in 4 bytes)- encolsed in  a '255'-masking -  to the serial Object of MAX/MSP/Jitter
{
    serialWrite(255);
    for(i = 0; i < 26; i++)
    {
      serialWrite(binaryArray[i]);
      binaryArray[i] = 0;
      grayArray[i] = 0; 
    }
    
    serialWrite(128);
}

/*
void resetRoutine() //to be filled for external reset via max/msp
{
 
  
}
*/

unfortunally this code/device/max produces false position data abou every 100 requests...which should be filtered by an mean-filtern on the max/msp side.....

stephan