[sam] bugfix for SPI on SAM3*. Extended API for SPI master devices is in ALPHA, to be validated.

This commit is contained in:
Cristian Maglie 2012-04-24 09:31:50 +02:00
parent d6c57415a3
commit 33870d3aae
5 changed files with 139 additions and 50 deletions

View File

@ -10,41 +10,87 @@
#include "SPI.h"
SPIClass::SPIClass(Spi *_spi, uint32_t _id, void(*_initCb)(void)) :
spi(_spi), id(_id), initCb(_initCb) {
// Empty
SPIClass::SPIClass(Spi *_spi, uint32_t _id, void(*_initCb)(void), uint32_t *_ss) :
spi(_spi), id(_id), initCb(_initCb)
{
for (int i=0; i<SPI_CHANNELS_NUM; i++)
ssPins[i] = _ss[i];
}
void SPIClass::begin() {
initCb();
// Set CS on NPCS3
SPI_Configure(spi, id, SPI_MR_MSTR | SPI_MR_PCS(0x07));
SPI_Enable( spi);
SPI_Configure(spi, id, SPI_MR_MSTR | SPI_MR_PS);
SPI_Enable(spi);
setClockDivider(1);
setDataMode(0);
}
void SPIClass::addSlave(uint8_t _channel) {
uint32_t pin = ssPins[_channel];
if (pin == 0)
return;
PIO_Configure(g_APinDescription[pin].pPort,
g_APinDescription[pin].ulPinType,
g_APinDescription[pin].ulPin,
g_APinDescription[pin].ulPinConfiguration);
}
void SPIClass::end() {
SPI_Disable( spi);
SPI_Disable(spi);
}
void SPIClass::setBitOrder(uint8_t bitOrder) {
setBitOrder(bitOrder, 0);
setBitOrder(bitOrder, 1);
setBitOrder(bitOrder, 2);
setBitOrder(bitOrder, 3);
}
void SPIClass::setBitOrder(uint8_t bitOrder, uint8_t _channel) {
// Not supported
}
void SPIClass::setDataMode(uint8_t _mode) {
mode = _mode;
SPI_ConfigureNPCS(spi, 3, mode | SPI_CSR_SCBR(divider));
setDataMode(_mode, 0);
setDataMode(_mode, 1);
setDataMode(_mode, 2);
setDataMode(_mode, 3);
}
void SPIClass::setDataMode(uint8_t _mode, uint8_t _channel) {
mode[_channel] = _mode | SPI_CSR_CSAAT;
SPI_ConfigureNPCS(spi, _channel, mode[_channel] | SPI_CSR_SCBR(divider[_channel]));
}
void SPIClass::setClockDivider(uint8_t _divider) {
divider = _divider;
SPI_ConfigureNPCS(spi, 3, mode | SPI_CSR_SCBR(divider));
setClockDivider(_divider, 0);
setClockDivider(_divider, 1);
setClockDivider(_divider, 2);
setClockDivider(_divider, 3);
}
byte SPIClass::transfer(byte _data) {
SPI_Write(spi, 0, _data);
return SPI_Read(spi);
void SPIClass::setClockDivider(uint8_t _divider, uint8_t _channel) {
divider[_channel] = _divider;
SPI_ConfigureNPCS(spi, _channel, mode[_channel] | SPI_CSR_SCBR(divider[_channel]));
}
byte SPIClass::transfer(byte _data, uint8_t _channel, bool _last) {
uint32_t d = _data | SPI_PCS(_channel);
if (_last)
d |= SPI_TDR_LASTXFER;
// SPI_Write(spi, _channel, _data);
while ((spi->SPI_SR & SPI_SR_TDRE) == 0)
;
spi->SPI_TDR = d;
// return SPI_Read(spi);
while ((spi->SPI_SR & SPI_SR_RDRF) == 0)
;
d = spi->SPI_RDR;
return d & 0xFF;
}
void SPIClass::attachInterrupt(void) {
@ -71,5 +117,12 @@ static void SPI_0_Init(void) {
g_APinDescription[PIN_SPI_SCK].ulPinConfiguration);
}
SPIClass SPI_0(SPI_INTERFACE, SPI_INTERFACE_ID, SPI_0_Init);
uint32_t SPI_0_SS[] = {
PIN_SPI_SS0,
PIN_SPI_SS1,
PIN_SPI_SS2,
PIN_SPI_SS3
};
SPIClass SPI_0(SPI_INTERFACE, SPI_INTERFACE_ID, SPI_0_Init, SPI_0_SS);
#endif

View File

@ -14,45 +14,42 @@
#include "variant.h"
#include <stdio.h>
#define SPI_CLOCK_DIV4 0x00
#define SPI_CLOCK_DIV16 0x01
#define SPI_CLOCK_DIV64 0x02
#define SPI_CLOCK_DIV128 0x03
#define SPI_CLOCK_DIV2 0x04
#define SPI_CLOCK_DIV8 0x05
#define SPI_CLOCK_DIV32 0x06
#define SPI_CLOCK_DIV64 0x07
#define SPI_MODE0 0x00
#define SPI_MODE1 0x02
#define SPI_MODE2 0x01
#define SPI_MODE1 0x01
#define SPI_MODE2 0x02
#define SPI_MODE3 0x03
#define SPI_MODE_MASK 0x03 // CPOL = bit 3, CPHA = bit 2 on SPCR
#define SPI_CLOCK_MASK 0x03 // SPR1 = bit 1, SPR0 = bit 0 on SPCR
#define SPI_2XCLOCK_MASK 0x01 // SPI2X = bit 0 on SPSR
class SPIClass {
public:
SPIClass(Spi *_spi, uint32_t _id, void(*_initCb)(void));
SPIClass(Spi *_spi, uint32_t _id, void(*_initCb)(void), uint32_t *_ss);
byte transfer(byte _data);
byte transfer(byte _data, uint8_t _channel = 0, bool _last = true);
// SPI Configuration methods
void attachInterrupt(void);
void detachInterrupt(void); // Default
void detachInterrupt(void);
void begin(void); // Default
void begin(void);
void addSlave(uint8_t _channel);
void end(void);
// These methods sets the same parameters on all channels
void setBitOrder(uint8_t);
void setDataMode(uint8_t);
void setClockDivider(uint8_t);
// These methods sets a parameter on a single channel
void setBitOrder(uint8_t, uint8_t _channel);
void setDataMode(uint8_t, uint8_t _channel);
void setClockDivider(uint8_t, uint8_t _channel);
private:
Spi *spi;
uint32_t id, divider, mode;
uint32_t id;
uint32_t divider[SPI_CHANNELS_NUM];
uint32_t mode[SPI_CHANNELS_NUM];
uint32_t ssPins[SPI_CHANNELS_NUM];
void (*initCb)(void);
};

View File

@ -0,0 +1,39 @@
#include <SPI.h>
#define FLASH_SPI_CHAN 3
void setup() {
Serial1.begin(9600);
SPI_0.begin();
SPI_0.addSlave(FLASH_SPI_CHAN);
SPI_0.setDataMode(SPI_MODE2, FLASH_SPI_CHAN);
SPI_0.setClockDivider(2); // We are too fast with 1
}
void loop() {
Serial1.println("Sending 'Identify' cmd to flash => 9F");
// Send cmd and receive response on the same transaction
// Parameter "false" keeps the SS pin active
SPI_0.transfer(0x9f, FLASH_SPI_CHAN, false);
char a1 = SPI_0.transfer(0x00, FLASH_SPI_CHAN, false);
char a2 = SPI_0.transfer(0x00, FLASH_SPI_CHAN, false);
char a3 = SPI_0.transfer(0x00, FLASH_SPI_CHAN, false);
char a4 = SPI_0.transfer(0x00, FLASH_SPI_CHAN, false);
char a5 = SPI_0.transfer(0x00, FLASH_SPI_CHAN);
Serial1.print("Received signature: ");
Serial1.print(a1, HEX);
Serial1.print(" ");
Serial1.print(a2, HEX);
Serial1.print(" ");
Serial1.print(a3, HEX);
Serial1.print(" ");
Serial1.print(a4, HEX);
Serial1.print(" ");
Serial1.print(a5, HEX);
Serial1.println();
delay(1000);
}

View File

@ -6,12 +6,13 @@
# Datatypes (KEYWORD1)
#######################################
SPI KEYWORD1
SPI_0 KEYWORD1
#######################################
# Methods and Functions (KEYWORD2)
#######################################
begin KEYWORD2
addSlave KEYWORD2
end KEYWORD2
transfer KEYWORD2
setBitOrder KEYWORD2
@ -22,14 +23,6 @@ setClockDivider KEYWORD2
#######################################
# Constants (LITERAL1)
#######################################
SPI_CLOCK_DIV4 LITERAL1
SPI_CLOCK_DIV16 LITERAL1
SPI_CLOCK_DIV64 LITERAL1
SPI_CLOCK_DIV128 LITERAL1
SPI_CLOCK_DIV2 LITERAL1
SPI_CLOCK_DIV8 LITERAL1
SPI_CLOCK_DIV32 LITERAL1
SPI_CLOCK_DIV64 LITERAL1
SPI_MODE0 LITERAL1
SPI_MODE1 LITERAL1
SPI_MODE2 LITERAL1

View File

@ -82,12 +82,19 @@
#define SPI_INTERFACE SPI0
#define SPI_INTERFACE_ID ID_SPI0
#define PIN_SPI_SS (77u)
#define SPI_CHANNELS_NUM 4
#define PIN_SPI_SS0 (77u)
#define PIN_SPI_SS1 (4u)
#define PIN_SPI_SS2 (0u)
#define PIN_SPI_SS3 (78u)
#define PIN_SPI_MOSI (75u)
#define PIN_SPI_MISO (74u)
#define PIN_SPI_SCK (76u)
static const uint8_t SS = PIN_SPI_SS ;
static const uint8_t SS = PIN_SPI_SS0 ;
static const uint8_t SS1 = PIN_SPI_SS1 ;
static const uint8_t SS2 = PIN_SPI_SS2 ;
static const uint8_t SS3 = PIN_SPI_SS3 ;
static const uint8_t MOSI = PIN_SPI_MOSI ;
static const uint8_t MISO = PIN_SPI_MISO ;
static const uint8_t SCK = PIN_SPI_SCK ;