ss1969
Posts: 5
Joined: Sat Sep 24, 2016 3:44 pm

soft SPI works but hard dont?RPI3

Sat Sep 24, 2016 4:15 pm

Hi all,

I've connected a si4438 rf controller on RPI3 SPI0(miso,mosi,sclk,ce0, some other gpios etc), and now soft gpio emulated SPI works fine.
But when I changed to hard spi, It doesn't work. BTW, I don't have a scope :( :( :(
I'm sure spi mode should be 0.

thanks for any suggestions. here's my key functions below:


Software emulated read/write, works fine:

Code: Select all

int radio_hal_SpiWriteByte(radioCtrlHandle* handle, uint8_t byteToWrite)
{
	unsigned char bit_ctr;

	for(bit_ctr=0;bit_ctr<8;bit_ctr++) // output 8-bit
	{
		if (byteToWrite&0x80){
			GPIOWrite(handle->pins.RF446x_SDI_PORT, GPIO_PIN_SET);
		}
		else{
			GPIOWrite(handle->pins.RF446x_SDI_PORT, GPIO_PIN_RESET);
		}

		byteToWrite = (byteToWrite << 1);			// shift next bit into MSB..
		usleep(1);
		GPIOWrite(handle->pins.RF446x_SCLK_PORT, GPIO_PIN_SET);
		usleep(1);
		GPIOWrite(handle->pins.RF446x_SCLK_PORT, GPIO_PIN_RESET);
		usleep(1);
	}
	return 0;
}


int radio_hal_SpiReadByte(radioCtrlHandle* handle, uint8_t* byteToRead)
{
	unsigned char bit_ctr;

	for(bit_ctr=0;bit_ctr<8;bit_ctr++) // output 8-bit
	{
		*byteToRead = (*byteToRead << 1);			// shift next bit into MSB..
		GPIOWrite(handle->pins.RF446x_SCLK_PORT, GPIO_PIN_SET);
		usleep(1);

		if (GPIORead(handle->pins.RF446x_SDO_PORT) != 0){
			*byteToRead |= 0x01;
		}
		else{
			*byteToRead &= ~0x01;
		}

		GPIOWrite(handle->pins.RF446x_SCLK_PORT, GPIO_PIN_RESET);
		usleep(1);
	}

	return 0;
}
CS is controlled by gpio as below:
I've tried initialize spi device with SPI_NO_CS flag and control CS manually in hard spi mode,
or without SPI_NO_CS flag and remarked gpio-cs-read-write functions,
but both not working.

Code: Select all

		
                radio_hal_ClearNsel(handle);
		radio_hal_SpiWriteByte(handle, 0x44);    //read CMD buffer
		radio_hal_SpiReadByte(handle, &ctsVal);
		radio_hal_SetNsel(handle);

hard spi functions:

Code: Select all

int spiInitialize(	spiCtrlHandle* handle,
						const char *device,
						const uint8_t mode,
						const uint8_t bits,
						const int32_t speed,
						const uint16_t delay)
{
	int ret = 0;

	/* device */
	handle->fd = open(device, O_RDWR);
	if (handle->fd < 0)
		syslog(LOG_LEVEL_FAIL, "FAIL:SPI:can't open %s\n", device);

	/* spi mode */
	ret = ioctl(handle->fd, SPI_IOC_WR_MODE, &mode);
	if(ret==-1)
		syslog(LOG_LEVEL_FAIL, "FAIL:SPI:can't set spi mode\n");

	if(ioctl(handle->fd, SPI_IOC_RD_MODE, &mode)<0)
		syslog(LOG_LEVEL_WARNING, "WARN:SPI:can't get spi mode\n");

	/* bits per word */
	ret = ioctl(handle->fd, SPI_IOC_WR_BITS_PER_WORD, &bits);
	if(ret==-1)
		syslog(LOG_LEVEL_FAIL, "FAIL:SPI:can't set bits per word\n");
	if(ioctl(handle->fd, SPI_IOC_RD_BITS_PER_WORD, &bits)<0)
		syslog(LOG_LEVEL_WARNING, "WARN:SPI:can't get bits per word\n");

	/* max speed hz */
	ret = ioctl(handle->fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed);
	if(ret==-1)
		syslog(LOG_LEVEL_FAIL, "FAIL:SPI:can't set max speed hz\n");
	if(ioctl(handle->fd, SPI_IOC_RD_MAX_SPEED_HZ, &speed)<0)
		syslog(LOG_LEVEL_WARNING, "WARN:SPI:can't get max speed hz\n");

	if(ret==-1)	return ret;

	handle->bits = bits;
	handle->speed = speed;
	handle->delay = delay;

	return 0;
}


int spiTransfer(spiCtrlHandle* handle, uint8_t* txData, uint8_t *rxBuf, int len)
{
    int ret;

    struct spi_ioc_transfer tr = {
        .tx_buf = (unsigned long)txData,
        .rx_buf = (unsigned long)rxBuf,
        .len = len,
        .delay_usecs = handle->delay,
        .speed_hz = handle->speed,
        .bits_per_word = handle->bits,
    };

    ret = ioctl(handle->fd, SPI_IOC_MESSAGE(1), &tr);

    return ret;
}
how hard spi initialized:

Code: Select all

spiInitialize(hSpi, "/dev/spidev0.0", SPI_MODE_0, 8, 500000, 0);
how hard spi functions called:‘

Code: Select all

radio_hal_SpiWriteByte(uint8_t byteToWrite)
      spiTransfer(handle->pins.handle, &byteToWrite, NULL, 1);


radio_hal_SpiReadByte(uint8_t* byteToRead)
      spiTransfer(handle->pins.handle, NULL, byteToRead, 1);

StuartF
Posts: 30
Joined: Sun Feb 02, 2014 5:41 pm

Re: soft SPI works but hard dont?RPI3

Mon Sep 26, 2016 2:05 pm

In your spiTransfer function, try adding

Code: Select all

.cs_change = 0
.pad = 0
to struct spi_ioc_transfer tr .

User avatar
joan
Posts: 14473
Joined: Thu Jul 05, 2012 5:09 pm
Location: UK

Re: soft SPI works but hard dont?RPI3

Mon Sep 26, 2016 3:32 pm

If you slow the SPI speed down to about 50 kbps you could check the waveform with http://abyz.co.uk/rpi/pigpio/piscope.html

ss1969
Posts: 5
Joined: Sat Sep 24, 2016 3:44 pm

Re: soft SPI works but hard dont?RPI3

Wed Sep 28, 2016 4:00 am

StuartF wrote:In your spiTransfer function, try adding

Code: Select all

.cs_change = 0
.pad = 0
to struct spi_ioc_transfer tr .
I made it work by: nCS controlled manually by gpio(other spi signals by hardware), and found the difference between the right and wrong behavior while initialize si4438:
right: cs pulled 0 before transfer byte 0x0, and keep to 0 a longtime while reading data until data is 0xFF;
wrong: cs pulled 0 before transfer byte 0x0, and immediately go back to 1 after tx, push to 0 again when read.

I've added .cs_change=0 and .pad = 0, but it doesn't fix the problem. I'll keep looking.

ss1969
Posts: 5
Joined: Sat Sep 24, 2016 3:44 pm

Re: soft SPI works but hard dont?RPI3

Wed Sep 28, 2016 4:00 am

joan wrote:If you slow the SPI speed down to about 50 kbps you could check the waveform with http://abyz.co.uk/rpi/pigpio/piscope.html
thanks! I'll try this lib.

ss1969
Posts: 5
Joined: Sat Sep 24, 2016 3:44 pm

Re: soft SPI works but hard dont?RPI3

Wed Sep 28, 2016 7:59 am

StuartF wrote:In your spiTransfer function, try adding

Code: Select all

.cs_change = 0
.pad = 0
to struct spi_ioc_transfer tr .
here's a picture with right(23) / wrong nCS(CE0, .cs_change=1) signal.
nCS.png
nCS.png (21.1 KiB) Viewed 1406 times
here's how soft cs controlled, original silabs si4438 initialize code

Code: Select all

uint8_t radio_comm_GetResp(radioCtrlHandle *handle, uint8_t byteCount, uint8_t* pData)
{
	uint8_t ctsVal = 0;
	uint16_t errCnt = RADIO_CTS_TIMEOUT;

	while (errCnt != 0){      //wait until radio IC is ready with the data
		radio_hal_ClearNsel(handle);
		radio_hal_SpiWriteByte(handle, 0x44);    //read CMD buffer
		radio_hal_SpiReadByte(handle, &ctsVal);
		if (ctsVal == 0xFF){
			if (byteCount){
				radio_hal_SpiReadData(handle, byteCount, pData);
			}
			radio_hal_SetNsel(handle);
			break;
		}
		radio_hal_SetNsel(handle);
		errCnt--;
	}
}
so..do I have any change to use hard nCS now?

User avatar
joan
Posts: 14473
Joined: Thu Jul 05, 2012 5:09 pm
Location: UK

Re: soft SPI works but hard dont?RPI3

Wed Sep 28, 2016 8:23 am

wrong: cs pulled 0 before transfer byte 0x0, and immediately go back to 1 after tx, push to 0 again when read.
That is actually correct behaviour. A write followed by a read is two SPI transactions and CS will be deasserted between them.

To gave a single CS assertion you would need to do a two byte transfer.

If you don't know when the radio will be ready then you have no choice other than bit banging all of SPI or at least bit banging the CS line.

ss1969
Posts: 5
Joined: Sat Sep 24, 2016 3:44 pm

Re: soft SPI works but hard dont?RPI3

Thu Sep 29, 2016 11:28 am

joan wrote:
wrong: cs pulled 0 before transfer byte 0x0, and immediately go back to 1 after tx, push to 0 again when read.
That is actually correct behaviour. A write followed by a read is two SPI transactions and CS will be deasserted between them.

To gave a single CS assertion you would need to do a two byte transfer.

If you don't know when the radio will be ready then you have no choice other than bit banging all of SPI or at least bit banging the CS line.
Got it. Now i'm bit banging the nCS line and it works fine. I'll accept this.

Return to “Interfacing (DSI, CSI, I2C, etc.)”