Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
SPI functions for Pinguino
22-08-2012, 04:30 PM,
#1
SPI functions for Pinguino
Hi there,

has anybody ever seriously used the SPI functions that Pinguino provides to transfer data from a device (.init(), .transfer(), .read(), .write())? With an SPI device connected to UEXT?

I suppose the functions exist to make using SPI easier. Though my findings on the net suggest that everybody confronted with SPI communication on the Pinguino resorted to a native implementation.

Right now, I'm right on the way to code it natively too out of mere frustration with the lack of documentation and no usable samples at all. If there's no information about them other than the source files, there's no reason at all to use Pinguino. I can also code it natively. Where's the point of having such a library then?

I'd hope I miss something, but honestly, I doubt it. If the former is the case, I'm very happy to hear about that.

Thanks,
Markus
Reply
22-08-2012, 05:00 PM,
#2
RE: SPI functions for Pinguino
Not sure if this helps: I'm currently using the SPI functions for P32 for sending data to an OLED display (not for receiving, and not on the UEXT connector but on pins D11/D13).

I use more or less the following code:
Code:
void setup()
{
   SPI.begin();
}

void loop()
{
  // get 16 bit value via CDC
  // [...]
  SPI.transfer(value >> 8);
  SPI.transfer(value & 0xff);
}

So far it works flawlessly. I just had to increase the value in the SPI_clock() call in line 238 of spi.c to get maximum speed.
(of course, ideally SPI.clock() should be exposed to the IDE)
Reply
22-08-2012, 07:35 PM,
#3
RE: SPI functions for Pinguino
I use them, except I only - currently - need init read & write so I'm not really seeing any big gain over doing it "native". Well, I suppose init saved me some hassle Smile

My device is on UEXT though I'm not sure why that really matters in this context.

John
Reply
24-08-2012, 03:05 PM,
#4
RE: SPI functions for Pinguino
Thanks for your replies.

I have some presumably very simple code for my MX220 here, yet I'm not sure if this generally works with Pinguino.

I'm using the following UEXT pins for SPI

10 (CS/SSEL)
8 (SDO1/MOSI)
7 (SDI1/MISO)
9 (SCK1/SCK)

as well as Vcc from pin 1 and Gnd from pin 2. According to the docs around from Olimex, this should be correct.

Code:
// Presumably simple test script for the ADXL345 gyro

#define CS 13

char POWER_CTL = 0x2D;
char DATA_FORMAT = 0x31;

unsigned char data;

void setup(){
  SPI.init();
  pinMode(CS, OUTPUT);
  digitalWrite(CS, HIGH);
  writeRegister(DATA_FORMAT, 0b00000001);
  delay(10);
  writeRegister(POWER_CTL, 0b00001000);
  delay(10);
}

void loop(){
  readRegister(DATA_FORMAT, data);
  CDC.printf("DATA_FORMAT is\t0x%x.\r\n", data);
  delay(100);
}

void writeRegister(char registerAddress, char value){
  digitalWrite(CS, LOW);
  SPI.write(registerAddress);
  SPI.write(value);
  digitalWrite(CS, HIGH);
}

void readRegister(char registerAddress, char value) {
  registerAddress |= 0x80;
  digitalWrite(CS, LOW);
  SPI.write(registerAddress);
  value = SPI.read();
  digitalWrite(CS, HIGH);
}

Any thoughts on that?

Thanks in advance,
Markus
Reply
24-08-2012, 09:21 PM, (This post was last modified: 24-08-2012, 09:31 PM by pingotg.)
#5
RE: SPI functions for Pinguino
I'm using an OTG so my UEXT CS is another pin but are you sure your CS of 13 is right?

BTW, I think you can probably use the returned value from SPI.write instead of also calling SPI.read.

edit: looking at digitalw.c I suspect you want CS as 20 (i.e. port RA7). In case you haven't a 'scope, even a multimeter will let you check a pin's voltage so you can check UEXT-CS is doing as you need, and just leave it at a level (high or low) for a long time as the device "won't care" enough to matter.

John
Reply
25-08-2012, 10:19 PM,
#6
RE: SPI functions for Pinguino
Thats right John, its indeed 20. I mixed this up with pin number on the MX220 chip. Thanks for spotting that.

Furthermore, the device needs the SCK polarity reversed.

Nevertheless, it still doesn't work yet. I can see CS works, SCK has the right polarity now, there's the correct address byte on the MOSI line, though no data on MISO still.

Taking the return value of SPI.write() instead of using SPI.read() doesn't make no difference as well.

To prevent any accidental inversion of MISO and MOSI, I also connected it the other way round (to no avail).

I don't have a clue right now what's going wrong here.
Reply
26-08-2012, 03:20 PM,
#7
RE: SPI functions for Pinguino
There are other SPI settings, maybe one of those needs changing?

So many settings/options.... such a pain in the ****. Why can't the hardware guys pick ONE way instead of making endless pointless work and causing delays in projects?

BTW I was asking this 30 years ago and there never was any good answer Sad

John
Reply
28-08-2012, 12:36 AM,
#8
RE: SPI functions for Pinguino
Well, it was the global variables (denoting the register addresses). They have to be declared either static or const. Otherwise their value will be different when I read them, consequently I end up reading a different address, thus I don't get a sensor response.

I've seen quite a bit of weirdness, and -O3 -ffunction-sections -fdata-sections -Wl,--gc-sections don't increase my confidence. If I try to change one of them, Pinguino gives me a linker error. I'd rather use -O0, especially when encountering strange issues like the USB code placement problem I'm facing here.

Now here's the code for the ADXL 345 acceleration sensor in its working state:

Code:
/*-----------------------------------------------------
Author:      MarSch
             <pinguino.666.brainbug@spamgourmet.org>
Date:        25/Aug/2012
Description: Simple interfacing sketch for the
             ADXL345 acceleration sensor.
Notes:       Code partly taken from
             http://www.sparkfun.com/tutorials/240            

-----------------------------------------------------*/

// Assign the Chip Select signal to pin 20.
#define CS 20

// Pinguino requires the variables to be explicitely declared const or static,
// otherwise its values are incorrect when used at readRegister().
// This makes no sense. Might be a bug.
const char POWER_CTL = 0x2D;   // Power Control Register
const char DATA_FORMAT = 0x31; // Measuring Resolution
const char DATAX0 = 0x32;         // X-Axis Data 0
const char DATAX1 = 0x33;         // X-Axis Data 1
const char DATAY0 = 0x34;         // Y-Axis Data 0
const char DATAY1 = 0x35;         // Y-Axis Data 1
const char DATAZ0 = 0x36;         // Z-Axis Data 0
const char DATAZ1 = 0x37;         // Z-Axis Data 1

// This buffer will hold values read from the ADXL345 registers.
char values[10];
// These variables will be used to hold the x,y and z axis accelerometer values.
int x, y, z;
  
void setup(){
  // Initialize SPI properly
  InitializeSPI();  
    
  // Put the ADXL345 into +/- 4G range by writing the value 0x01 to the DATA_FORMAT register.
  writeRegister(DATA_FORMAT, 0x01);
  // Put the ADXL345 into Measurement Mode by writing 0x08 to the POWER_CTL register.
  writeRegister(POWER_CTL, 0x08);
}

void loop(){
  // Reading 6 bytes of data starting at register DATAX0 will retrieve the x, y and z
  // acceleration values from the ADXL345.
  // The results of the read operation will get stored to the values[] buffer.
  readRegister(DATAX0, 6, values);

  // The ADXL345 gives 10-bit acceleration values, but they are stored as bytes (8-bits).
  // To get the full value, two bytes must be combined for each axis.
  // The X value is stored in values[0] and values[1].
  x = ((int)values[1]<<8)|(int)values[0];
  // The Y value is stored in values[2] and values[3].
  y = ((int)values[3]<<8)|(int)values[2];
  // The Z value is stored in values[4] and values[5].
  z = ((int)values[5]<<8)|(int)values[4];
    
  // Print the results to the terminal.
  CDC.printf("X:%4d, Y: %4d, Z: %4d\r\n", x, y, z);  
  
  // Slack around.
  delay(5);
}


void InitializeSPI() {
  // Initialize SPI
  SPI.init();
  
  // Configure the SPI connection for the ADXL345 (SPI mode 3).
  SPI1CONCLR = 0x8000;              // Turn off SPI
  SPI1CONSET |= 0b001000000;
  SPI1CONCLR = 0x100;               // Clock edge bit(8) to 0                            
  SPI1CONCLR = 0x40;                // Clock polarity bit(6) to 0
  //SPI2CONSET = 0x100;             // Clock edge bit(8) to 1                            
  SPI1CONSET = 0x40;                // Clock polarity bit(6) to 1
  SPI1CONSET = 0x8000;              // Turn SPI mode back on after register changes
  
  // Configure the Chip select pin.
  pinMode(CS, OUTPUT);
  digitalWrite(CS, HIGH);
}

void writeRegister(char registerAddress, char value) {

  // Set Chip Select pin low to signal the beginning of an SPI packet.
  digitalWrite(CS, LOW);
  
  // Transfer the register address over SPI.
  SPI.write(registerAddress);
  
  // Transfer the desired register value over SPI.
  SPI.write(value);
  
  // Set the Chip Select pin high to signal the end of an SPI packet.
  digitalWrite(CS, HIGH);
}

void readRegister(char registerAddress, int numBytes, char * values) {
  int i;
  
  // Since we're performing a read operation, the most significant bit of the
  // register address should be set.
  registerAddress |= 0x80;
  
  // If we're doing a multi-byte read, bit 6 needs to be set as well.
  if (numBytes > 1)
    registerAddress |= 0x40;
  
  // Set the Chip select pin low to start an SPI packet.
  digitalWrite(CS, LOW);
  
  // Transfer the starting register address that needs to be read.
  SPI.write(registerAddress);
  
  // Continue to read registers until we've read the number specified, storing
  // the results to the input buffer.
  for (i = 0; i < numBytes; i++)
    values[i] = SPI.read();

  //Set the Chips Select pin high to end the SPI packet.
  digitalWrite(CS, HIGH);
  
  // THIS IS ONLY NECESSARY TO GET THE ALIGNMENT RIGHT FOR PINGUINO MX 220.
  // THE DEVICE WON'T ENUMERATE CORRECTLY AS USB OTHERWISE.
  nop(); nop();  
}
Reply
28-08-2012, 12:49 AM, (This post was last modified: 28-08-2012, 12:54 AM by pingotg.)
#9
RE: SPI functions for Pinguino
Oh dear. That should not happen in C. Something is wrong, such as the options given to the C compiler or it is broken Sad

Generally instead of
const char x = Y;
you may as well use
#define x Y
as you'll usually get smaller/faster code. On a good day a compiler may figure it out and make the code anyway but it sounds like something is going wrong.

You should be able to leave out the const in your sample and code should still work. (It's OK to have it in, but it should not be needed.)

Still if it's now working I suppose that'll do.

Optimising can be risky, especially -O3 and the like. Unless you need to, I wouldn't use it.

BTW as a good habit, you might like to add signed or unsigned to char values[10], or indeed any other char where you widen its value - here you cast using (int) - as you want to control how it is widened ("promoted").

John
Reply
28-08-2012, 10:26 AM,
#10
RE: SPI functions for Pinguino
Hi John,

unless I initialize the register addresses as const or static, it goes wrong. Of course I could #define them as well. That's what I'll probably do.

I wasn't clear enough about the optimization issue: I'm sharing your concern about it, nevertheless, the above flags are the default in Makefile32.{linux,win32}. As soon as I change anyone of them, Pinguino gives me a linking error.
Reply


Forum Jump:


Users browsing this thread: 1 Guest(s)