ASF4 SPI CS Problem

Go To Last Post
4 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hey guys,

 

So I'm currently using an SAME 54 Xplained Pro to develop a proof of concept for communication with two I/O Expanders. I'm trying to communicate with the two expanders over parallel SPI so that they share a MOSI, MISO, and SCK, but have different, software controlled CS lines. I'm using spi_m_sync_transfer() because I wasn't able to get io_read/write() to work.

 

Anyway, my problem is that no matter what I try to do, I can't separate the chip select lines. No matter what I change, anytime I do an SPI transfer to an individual expander, both CS lines go low, causing it to write to both.

 

I originally started by manually setting the gpio line to low when I was transferring and moving it back to high, but later I realized that even without my software toggling, the driver/hardware/something automatically toggles it. This isn't a problem for a single slave, but with parallel slaves, I need to be able to separately write to each expander. The SPI driver has a CTRLB.MSSEN register that controls hardware controlled chip selects. However, this defaults to 0, allowing the user to control the CS lines. Another potential solution could be the gpio_set_pin_function, which I've tried using both GPIO_PIN_FUNCTION_OFF and GPIO_PIN_FUNCTION_B (from reading someone's post that suggested it), but I haven't been able to find any documentation on what each of the different pin functions are for. I've also tried moving around which pins I'm using on the CS line onto different GPIO's/CS/extension headers, but that shouldn't matter and it didn't help.

 

I've heard about and experienced myself a lot of issues with ASF4's SPI Driver, so it could easily be that. Although I'm thinking it's something with the SAME54XPro, but I've yet to figure out what that could be.

 

Any suggestions would be greatly appreciated.

This topic has a solution.

rlvnt_clwn

Last Edited: Thu. Jul 18, 2019 - 01:26 PM
This reply has been marked as the solution. 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

I used Start when I set up my SPI using the Pin Configurator.  I set the 3 SPI pins to "peripheral", but then just manually set my chip select line to digital output and initial state to high so it wasn't part of the peripheral, then just pulsed the pin low using gpio_set_pin_level(PINNAME, false/true) and that was all I needed.  The peripheral left that pin alone when I did that, so hopefully that can help you out.

 

Here is the code I created to initialize the SPI then write to a fram chip and it works great:

 

void initeeeprom(void)
{
//initialize the SPI interface to get peripheral ready to read and write to fram    
//some of these lines of code were taken from the driver_examples.c file generated by START when we added the SPI driver
//The defines for some of these commands are copied from hpi_spi.h

struct io_descriptor *io;
spi_m_sync_get_io_descriptor(&SPI_0, &io);
SPI_0_init();  //this call in driver_init.c initializes the spi0 and uses spi_m_sync_init()
spi_m_sync_enable(&SPI_0);
spi_m_sync_set_mode(&SPI_0,SPI_MODE_3); //set the spi to mode 3 (sets the clock/data phases)
spi_m_sync_set_baudrate(&SPI_0,1000000); //set baudrate to 10Mhz  NOTE: 1000000 is actually 10Mhz write, dont' know why have to chck this
spi_m_sync_set_char_size(&SPI_0,SPI_CHAR_SIZE_8);  //8 bit character size to write
spi_m_sync_set_data_order(&SPI_0,SPI_DATA_ORDER_MSB_1ST);
}
//=========================================================================================================================
void writeeeprom(uint32_t addr,uint8_t eedata)
{
//some of these lines of code were taken from the driver_examples.c file generated by START when we added the SPI driver
//The defines for some of these commands are copied from hpi_spi.h
uint8_t command;

struct io_descriptor *io;
spi_m_sync_get_io_descriptor(&SPI_0, &io);

gpio_set_pin_level(SPI0CS1,false); //must control the select manually
//write enable must be set before writing and this is a single write operation in itself (so do CS low CS high)
command=0x06; //write enable command
io_write(io, &command, 1);
gpio_set_pin_level(SPI0CS1,true); //must control the select manually
delay_us(1); //some time between cs pulses
//now do a write command which is command, address (24 bits), and data (8 bits)
gpio_set_pin_level(SPI0CS1,false); //must control the select manually
command=0x02; //write command
io_write(io, &command, 1);
command=(uint8_t)((addr&0x00ff0000)>>16); //send out bits 16-24 of address
io_write(io, &command, 1);
command=(uint8_t)((addr&0x0000ff00)>>8); //send out bits 8-15 of address
io_write(io, &command, 1);
command=(uint8_t)(addr&0x000000ff); //send out bits 0-7 of address
io_write(io, &command, 1);
//now send out data
io_write(io, &eedata, 1);
gpio_set_pin_level(SPI0CS1,true); //end of write command (must control the select manually)
}

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hey Nafai,

 

I just tried out your solution - changing the SPI Driver from Digital Output to Peripheral IO and it worked! Don't know why the driver wouldn't have been fixed earlier, but thanks!

rlvnt_clwn

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I know that on the SAM3 & SAM4 processors there is a register for the SPI_CS control, effectively IIRC you can have different configurations for different CS lines.

Meaning that you configure the SPI for each CS line. and then there is some trick to writing to a special register and by doing that you automatically set the SPI up for that specific peripheral.

That includes delay times between CS and data start, so in that case you want the CS line to be controlled by hardware rather than your code. t saves a lot of thinking.

We had one product were we used all 4 CS options with different clock speeds and different polarity. All the FW guys had to do was during initialization set all the SPI configs correct adn thenin the usage they wrote to a special register telling the SPI that that specific config was tobe used and then fire the first byte and the rest was done under interrupt. So as the ASF is just a usage example this is a thing that will make normal life easier.