I spent the last week trying to configure the SPI port but I am not able to do it works. I use the evaluation board AT91SAM7s-EK. The examples of the website are weird to understand and the datasheet is not very clear. The configuration is the simplest (without interrupt and DMA) but I don’t have idea how to get it works.
My configure is this:
[size=85]********************************************************************************
*
* program: setup_SPImaster
*
*Summary: It makes the configuration of the microcontroller
*
********************************************************************************/
#include "board.h"
#include "include/AT91SAM7S256.h"
#define DLYBCS ((unsigned int) 0x0A << 24) //Delay between chip select of aprox 2Tclk = 0,2us
#define SCBR0 ((unsigned int) 0x05 << 8) //Serial clock baud rate = MCK/SPCK (SPCK=20Mhz for slave0)
#define DLYBS0 ((unsigned int) 0x00 << 16) //Delay before SPCK by default 1/2 SPCK clock period
#define DLYBCT0 ((unsigned int) 0x00 << 24) //Delay between consecutive transfer (zero value-->Not delay)
#define LAN_SLAVE 0 //It is Choosen the slave 0 for the ECN28J60
//#define READER_SLAVE 1 //It is Choosen the slave 1 for the INDY R2000
extern void setup_SPImaster (void);
extern void spi_IrqHandler (void);
/********************************************************************************
*
*SETUP_SPIMASTER
********************************************************************************/
void setup_SPImaster (void){
AT91PS_SPI pSPI = AT91C_BASE_SPI; // Pointer to SPI structure
AT91PS_PIO pPIO = AT91C_BASE_PIOA; // Pointer to PIOA structure
AT91PS_AIC pAIC = AT91C_BASE_AIC; // Pointer to AIC structure
unsigned int PerA=0, PerB=0;
unsigned int mode, confcs0;
//(1) Initialization of AT91SAM7s256
// It asigns the pins that you want to have at SPI
PerA = (((unsigned int)AT91C_PA11_NPCS0)|
((unsigned int) AT91C_PA12_MISO) |
((unsigned int) AT91C_PA13_MOSI) |
((unsigned int) AT91C_PA14_SPCK) |
((unsigned int) AT91C_PA30_IRQ1)|
((unsigned int) AT91C_PA31_NPCS1));
PerB = ((unsigned int) AT91C_PA20_IRQ0);
AT91F_PIO_CfgPeriph (pPIO, PerA, PerB);
AT91F_SPI_Reset (pSPI);
//(2) Enable SPI in the PMC
// Enable the Peripheral Clock for SPI
AT91F_SPI_CfgPMC ();
//(3)Configuration of Master mode
//Conf_ Mode Register
mode= AT91C_SPI_MSTR |
AT91C_SPI_PS_VARIABLE|
//AT91C_SPI_PCSDEC |
AT91C_SPI_MODFDIS |
// AT91C_SPI_LLB | //local loopback
// AT91C_SPI_PCS |
DLYBCS;
AT91F_SPI_CfgMode(pSPI, mode);
//Conf_chipSelects
//Ethernet controller --> Chip Select 0
confcs0= // AT91C_SPI_CPOL |
AT91C_SPI_NCPHA |
AT91C_SPI_CSAAT |
AT91C_SPI_BITS_8 |
SCBR0 |
DLYBS0 |
DLYBCT0;
AT91F_SPI_CfgCs( pSPI, LAN_SLAVE, confcs0);
//Indy R2000 --> Chip Select 1 -- NOT DEFINED YET --
//AT91F_SPI_CfgCs( pSPI,READER_SLAVE, confcs1);
//(4)Enable SPI to transfer and receive data (pSPI->SPI_CR.SPIEN=1)
//AT91F_SPI_Enable (pSPI);
AT91F_SPI_Enable(AT91C_BASE_SPI);
/*///(5)Configuration Advanced Interrupt Controller (AIC) registers for SPI
// Set up AIC register
//Function spi_IrgHandler is assigned to SPI interrupt
// Set the interrupt source type and priority 7
AT91F_AIC_ConfigureIt (pAIC, AT91C_ID_SPI,7,AT91C_AIC_SRCTYPE_INT_POSITIVE_EDGE , spi_IrqHandler);
// Enable the SPI interrupt in AIC Interrupt Enable (0X00000020)
AT91F_AIC_EnableIt (pAIC, AT91C_ID_SPI);
//(6)Interrupt Enable Register(pSPI->SPI_IER)
AT91F_SPI_EnableIt (pSPI, (AT91C_SPI_RDRF | AT91C_SPI_TDRE | AT91C_SPI_OVRES |AT91C_SPI_TXEMPTY |AT91C_SPI_NSSR)); */[/size]
After this configuration, the register SPI_SR= 0x000102F2 and never changes. To initialize the SPI communication, I do the following steps
Poll TXEMPTY to verify if the register and the serializer are empty.
while (!(pSPI → SPI_SR & AT91C_SPI_TXEMPTY));
Write in the Transmission register
pSPI->SPI_TDR= TDframe;
Wait until RDRF=1
while (!(pSPI → SPI_SR & AT91C_SPI_RDRF);
Read the receiver register
u32 data;
data= pSPI->SPI_RDR
When I write in the SPI_TDR the data is copy to the SPI_RDR but the flag never change.
If I try to visualize any SPI signal by the oscilloscope I don’t get any result.
Thank you, I already read the topic and I could solve my problem, at least now I can see something in the scope. In the local loopback mode, when I visualize the MISO signal the shape is similar to the master clock (but with a lot of noise) in place of the MOSI. Why?
If you’re using loopback mode, the connection between MISO and MOSI takes place inside the chip, even before the PIO, so you shouldn’t be able to measure anything at the MISO-pin (maybe if you set it as output, but I’m not sure). What you see is probably leakage.
If you can send and receive data using loopback mode, you’re set. Try talking to some real devices instead of trying to find problems that aren’t there.
Yes, you’re right, In my project, I am using a real device. It is the ECN28J60 ethernet controller of Microchip. The problem of the ECN28J60 is its SPI because works completly different to AT91SAM7s256 SPI. The ECN28J60 works with 7 SPI commands. They are composed of 8 bits ‘frame’. When you are sending data on the MOSI line the MISO line is in high impedance and only after last bit has been sent you can received data on MISO. And this stuff is quite complex to manage.
Completely different? Many devices works like that. You first send a byte-command, then receive the response data. More specific, you send a command byte, wait for it to finish, send a dummy byte, wait for it to finish and then the response is available in the receive data register.
Humm, it is the first time that I use this kind of interface. I read some information about SPI and they tell you that the SPI was like a shift register where you always received a bit by bit sent.
Anyway the behaviour is quite strange because when I am reading a MAC register of the ECN28J60, its content is set in the dummy byte :shock: and the data byte is empty. It should be something wrong in my code…
It’s actually exactly like two shift register, one parallel in, serial out and one the other way. The key to understanding the function is that both of these are clocked simultaneously, thus for every serial clock-cycle, you send one bit and receive one bit.
However, if the device use 8-bit “frames”, nothing will be done until a whole frame is transferred.
So, if you send a byte, you automagically also receive one byte. If this byte has any real meaning is up to the protocol used by the device. Very often you first send a command byte during the first transfer(s), and the following transfer you receive a response byte. Note that you actually send two bytes and receive two bytes, although the second send-byte and the first receive byte is not meaningful.
I’m sorry if I’m over explaining it.
For testing purposes, just disable interrupts and go with the old reading/writing the data registers and waiting for transfer-complete. When you can actually read and write the slave-device you can then go on and implement the communication using interrupts and stuff.
After some attempts the result is still weird. When I try to read a MAC register after writing its value. The way that I use to visualize the content is with a scope ( one channel for the clock and the others for the MOSI and MISO line) because I don´t have a logic analizer.
For this reason, I do a while(1)-loop and I read continuosly the register previously wrote.
For the kind of register ETH the solution is perfect, to read the content you must send two bytes on the MOSI line.
MISO → 1st byte - High Impedance ; 2nd byte (dummy); 3rd byte (content of register).
When I visualize the MAC/MII register, Its content sometimes is showed in the 2nd dummy byte of the MOSI line and other times I only can see ‘zeros frame’. But never in the 3rd byte like Microchip told you.
If I write two or more registers MAC/MII, when I try to watch the content of the first of them, the last data write is showed in the 2nd dummy byte of the MOSI line
I have reviewed the connections and the configuration but all is right. Maybe, this behaviour is due to the way to visualize the SPI signals. What do you think?
To me it feels like it’s something wrong with the chip select. How do you control it? Are you sure it is inactive before sending the first command byte?
Humm, maybe because I am using the control made by the Master. For example,if you use a PIC microcontroller with the ECN28J60 the control of the chip select is made by I/O line.
You can let the SPI-peripheral handle the chip-select, or you could do it with a PIO-pin.
If you let SPI handle it, there are some different settings for it. You can have it inactivate after every transfer, but you probably don’t want that, or you can let it remain active but then you’ll need to set a certain bit before the last transfer to have it inactivate after that.
Well, it can be. But the AT91SAM7s256 has a bit called ‘LASTXFER’ in the Transmit Data Register, when this bit is set, the chip select is disabled after of transfer the data. In my case, this bit is only set in the last byte (dummy) that I send.
You could be rigth but this problem only happens when I read the MAC/MII register that they need two dummy bytes else is ok.