Pages: [1] 2   Go Down
Author Topic: Setting up the second SPI port on the Arduino Uno  (Read 1912 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
Newbie
*
Karma: 0
Posts: 12
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

As I understand it, there's a second hardware SPI port that's available for use on the ATMEGA328P, by configuring the regular USART to run in SPI master mode, which should in theory mean it's available on the Arduino Uno. I'll admit, I'm not much of a genius in configuring the registers, etc, but I figure there's gotta be somebody out there that's done this on an Arduino. Thoughts? I've got an LED string that I have running GREAT over the SPI port, but I need to access other devices and there's no provisions for chip select on the LEDs.

I'm getting my onfo on page 206 of http://www.atmel.com/Images/doc8271.pdf

Or do I just give up and set up AND gates and MAKE my LED strip have chip select?

Andy
Logged

Global Moderator
Offline Offline
Brattain Member
*****
Karma: 452
Posts: 18694
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

There's a slightly helpful application note here:

www.atmel.com/Images/doc2577.pdf

I'll see if I can make it work, since I can't easily find someone who has done it.
Logged

Global Moderator
Offline Offline
Brattain Member
*****
Karma: 452
Posts: 18694
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

That wasn't too hard. Example:

Code:
/*
Example of USART in SPI mode on the Atmega328.

Author:   Nick Gammon
Date:     12th April 2012
Version:   1.0

Licence: Released for public use.

Pins: D0 MISO (Rx)
      D1 MOSI (Tx)
      D4 SCK  (clock)
      D5 SS   (slave select)  <-- this can be changed

 Registers of interest:
 
 UDR0 - data register
 
 UCSR0A – USART Control and Status Register A
     Receive Complete, Transmit Complete, USART Data Register Empty
 
 UCSR0B – USART Control and Status Register B
     RX Complete Interrupt Enable, TX Complete Interrupt Enable, Data Register Empty Interrupt Enable ,
     Receiver Enable, Transmitter Enable
  
 UCSR0C – USART Control and Status Register C
     Mode Select (async, sync, SPI), Data Order, Clock Phase, Clock Polarity
 
 UBRR0L and UBRR0H - Baud Rate Registers - together are UBRR0 (16 bit)

*/
 
const byte MSPIM_SCK = 4;
const byte MSPIM_SS = 5;

// sends/receives one byte
byte MSPIMTransfer (byte c)
{
  // wait for transmitter ready
  while ((UCSR0A & _BV (UDRE0)) == 0)
    {}
    
  // send byte
  UDR0 = c;
  
  // wait for receiver ready
  while ((UCSR0A & _BV (RXC0)) == 0)
    {}
    
  // receive byte, return it
  return UDR0;
}  // end of MSPIMTransfer

// select slave, write a string, wait for transfer to complete, deselect slave
void spiWriteString (const char * str)
  {
  if (!str) return;  // Sanity Clause
  
  char c;

  // enable slave select
  digitalWrite (MSPIM_SS, LOW);
  
  // send the string
  while (c = *str++)
    MSPIMTransfer (c);
  
  // wait for all transmissions to finish
  while ((UCSR0A & _BV (TXC0)) == 0)
    {}

  // disable slave select
  digitalWrite (MSPIM_SS, HIGH);
  }  // end of spiWriteString
 
void setup()
  {
  pinMode (MSPIM_SS, OUTPUT);   // SS
  // must be zero before enabling the transmitter
  UBRR0 = 0;
  UCSR0A = _BV (TXC0);  // any old transmit now complete
  pinMode (MSPIM_SCK, OUTPUT);   // set XCK pin as output to enable master mode
  UCSR0C = _BV (UMSEL00) | _BV (UMSEL01);  // Master SPI mode
  UCSR0B = _BV (TXEN0) | _BV (RXEN0);  // transmit enable and receive enable
  // must be done last, see page 206
  UBRR0 = 3;  // 2 Mhz clock rate
  }  // end of setup

void loop()
  {
  spiWriteString ("hello, world!");
  }  // end of loop

Screenshot in operation:



The stuff in setup configures the USART.

spiWriteString shows the general idea of using it ... you select the slave (if wanted), then repeatedly call MSPIMTransfer to transfer each byte. It waits for the last one to finish (so we can deselect SS in an orderly way).

MSPIMTransfer sends/receives one byte - blocking.
« Last Edit: April 12, 2012, 12:48:30 am by Nick Gammon » Logged

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

Nick,

Thanks for posting the code to create SPI port on uart pins. I am, however, having a problem with it. I tried setting up a simple test. I am using an Arduino Uno w/no devices attached. Since I was having a problem, I tried this simple test using std SPI library, works as you would expect. I am using FTDI breakout from Sparkfun to read. hello there, hello there....

Code:
#include <SPI.h>
#include <SoftwareSerial.h>
SoftwareSerial DebugPort = SoftwareSerial(2,3);

char mystring[100]="hello there";
char mystring2[100]="";
void setup() {
  // put your setup code here, to run once:
  DebugPort.begin(9600);
  SPI.begin();
  SPI.setBitOrder(MSBFIRST);
  SPI.setClockDivider(SPI_CLOCK_DIV2);
  SPI.setDataMode(SPI_MODE0);
}

void loop() {
  uint8_t x=0;
  digitalWrite(SS,LOW);
 for(x;x<(strlen(mystring));x++){
  mystring2[ x ] = SPI.transfer( mystring [ x ] ) ;
 }
 digitalWrite(SS,HIGH);
 mystring2[x+1]='\0';
 DebugPort.println(mystring2);
}

*************
Then I tried a similar setup using the code you posted. On this I get an output of ......,......,...... (yes dots). Do you know what may be the problem?
************



Code:
#include <SoftwareSerial.h>
SoftwareSerial DebugPort = SoftwareSerial(2,3);
const byte MSPIM_SCK = 4;
const byte MSPIM_SS = 5;
char mystring[100]="hello there";
char mystring2[100]="";
// sends/receives one byte
char MSPIMTransfer (char c)
{
  // wait for transmitter ready
  while ((UCSR0A & _BV (UDRE0)) == 0)
    {}
    
  // send byte
  UDR0 = c;
  
  // wait for receiver ready
  while ((UCSR0A & _BV (RXC0)) == 0)
    {}
    
  // receive byte, return it
  return UDR0;
}  // end of MSPIMTransfer

// select slave, write a string, wait for transfer to complete, deselect slave
void spiWriteString (const char * str)
  {
  if (!str) return;  // Sanity Clause
  
  char c;

  // enable slave select
  digitalWrite (MSPIM_SS, LOW);
 // const char * mystr = str;
  uint8_t count =0;
  // send the string
  while (c = *str++){
   mystring[count] =MSPIMTransfer (c);
  }

  // wait for all transmissions to finish
 while ((UCSR0A & _BV (TXC0)) == 0)
    {}

  // disable slave select
  digitalWrite (MSPIM_SS, HIGH);
  }  // end of spiWriteString
 
void setup()
  {
  DebugPort.begin(9600);
  pinMode (MSPIM_SS, OUTPUT);   // SS
  // must be zero before enabling the transmitter
  UBRR0 = 0;
  UCSR0A = _BV (TXC0);  // any old transmit now complete
  pinMode (MSPIM_SCK, OUTPUT);   // set XCK pin as output to enable master mode
  UCSR0C = _BV (UMSEL00) | _BV (UMSEL01);  // Master SPI mode
  UCSR0B = _BV (TXEN0) | _BV (RXEN0);  // transmit enable and receive enable
  // must be done last, see page 206
  UBRR0 =3;// 3;  // 2 Mhz clock rate
  }  // end of setup

void loop()
  {
    
      uint8_t x=0;
  digitalWrite(MSPIM_SS,LOW);

 for(x;x<(strlen(mystring));x++){
  mystring2 [ x ] =MSPIMTransfer( mystring  [ x ] );
 }
 digitalWrite(MSPIM_SS,HIGH);
  mystring2[x+1]='\0';
  DebugPort.println(&mystring2[0]);  
}

Thanks,

-diesel

Moderator edit: [code] ... [/code] tags added. (Nick Gammon)
« Last Edit: February 05, 2013, 11:14:38 pm by Nick Gammon » Logged

Global Moderator
Offline Offline
Brattain Member
*****
Karma: 452
Posts: 18694
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Code:
  DebugPort.println(&mystring2[0]);   

Why not:

Code:
  DebugPort.println(mystring2);   

As you had in the working example.
Logged

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

Nick,

I was messing around with code trying to get it to work, that is why they were different.

I modified as you suggested, but same output......,......,. I did switch back to my first listed code and noticed for a short period of time it would output ......., .......,  then it went back to hello there. Maybe it is a timing thing? I saw something in the datasheet that it talks about setting up interrupts, are those necessary?

Thanks,

-diesel
Logged

Global Moderator
Offline Offline
Brattain Member
*****
Karma: 452
Posts: 18694
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
I am using FTDI breakout from Sparkfun to read.

Read what? The software serial output?

Software serial turns interrupts off for a while. Try using a faster debugging baud rate.

Also it isn't clear what is being echoed from where.
Logged

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

Nick,

The plan is to use the secondary spi port to use with SPI ram. First, I want to make sure it is working, so now I am just reading and writting from SoftwareSerial. I am attempting to write and read into the SPI port, which works using the hardware spi.

Thanks, I will give the higher baud rate a try.

-diesel

Logged

Global Moderator
Offline Offline
Brattain Member
*****
Karma: 452
Posts: 18694
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

It certainly should work, unfortunately sometimes debugging itself obscures what is happening.
Logged

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

Nick,

I put a logic analyzer on both so that you could see. I attached two images, 1st with Uart SPI and 2nd with Arduino std SPI. On the Uart SPI I get 255...255,\r,\n from serial. Nothing but 255 for the array of characters. On the Arduino std SPI I get ->hello there \r\n(although not perfect). The best software serial baud seemed to be 38400, I ranged from 9600-115200( best defined by what I received from Arduino SPI) . I also tried connecting the Arduino up with only 9v power supply, disconnecting usb, I thought that might be giving me interference, no change in output, still 255 from Uart SPI. Any other suggestions? I have a arduino mega 1280, perhaps I could give that a try w/the 2nd hardware serial port. Would I have to change the registers?

Thanks,

-diesel


* uartspi.jpg (273.24 KB, 1678x962 - viewed 21 times.)

* arduinostdspi.jpg (266.82 KB, 1678x962 - viewed 17 times.)
« Last Edit: February 07, 2013, 12:52:04 am by diesel » Logged

Global Moderator
Offline Offline
Brattain Member
*****
Karma: 452
Posts: 18694
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

OK, for me to reproduce that I need both ends. So far you have posted code for one of the devices. That isn't something that communicates with SPI RAM, right?
Logged

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

Nick,

I hooked up the SPI ram, it works on the arudino 328p, which is great, thanks! Unfortunately, I can't get it working on the mega 1280. The registers and bits seem to be the same. I looked over the datasheets for the 328 and the 1280, they both look same w/regards to UART in SPI mode. Do you know what maybe the problem?

Thanks,

-diesel
Logged

Global Moderator
Offline Offline
Brattain Member
*****
Karma: 452
Posts: 18694
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Ah, no I haven't looked closely at the registers for the Mega with respect to this. The fact that the subject line of each post is still "Setting up the second SPI port on the Arduino Uno" is obscuring somewhat the fact that we are talking about a Mega.
Logged

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

Nick,

I can start a new post if you like? I think that I have found the problem. XCKO is not mapped to an accessible pin. Ref. http://arduino.cc/en/Hacking/PinMapping2560 (which I believe has the same mapping as the 1280). If you search on XCK, none are mapped to an accessible pin. Are there any options of accessing the function of those pins?

Thanks,

-diesel
Logged

Global Moderator
Offline Offline
Brattain Member
*****
Karma: 452
Posts: 18694
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Looks like you are right. They haven't connected any of them to an external pin.

I don't know offhand of any way of making one pin "mirror" another. You could always bit-bang the SPI.
Logged

Pages: [1] 2   Go Up
Jump to: