Issues Subscribing to SPI Bus with GPIO as Chip Select

Hello,

I’m having issues trying to subscribe to an SPI bus in Open AT. However, I followed the ADL documentation very closely and am still having trouble.

#include "adl_global.h"
#include "adl_gpio.h"
#include "adl_bus.h"
#include "generated.h"

// globals
adl_tmr_t *mainTicker;
adl_busSPISettings_t SpiSettings =
{
		0,
		ADL_BUS_SPI_CLK_MODE_0,
		ADL_BUS_SPI_ADDR_CS_GPIO,
		ADL_BUS_SPI_CS_POL_HIGH,
		ADL_BUS_SPI_MSB_FIRST,
		ADL_IO_GPIO | 20,
		ADL_BUS_SPI_LOAD_UNUSED,
		ADL_BUS_SPI_DATA_BIDIR,
		ADL_BUS_SPI_MASTER_MODE,
		ADL_BUS_SPI_BUSY_UNUSED
};
s32 SpiHandle;

void initSPI(void)
{
	SpiHandle = adl_busSubscribe(ADL_BUS_ID_SPI,1,&SpiSettings);

	switch( SpiHandle ) {
	case ADL_RET_ERR_PARAM:
		adl_atSendResponse(ADL_AT_UNS, "ADL_RET_ERR_PARAM\n");
		break;
	case ADL_RET_ERR_ALREADY_SUBSCRIBED:
		adl_atSendResponse(ADL_AT_UNS, "ADL_RET_ERR_ALREADY_SUBSCRIBED\n");
		break;
	case ADL_RET_ERR_BAD_HDL:
		adl_atSendResponse(ADL_AT_UNS, "ADL_RET_ERR_BAD_HDL\n");
		break;
	case ADL_RET_ERR_NOT_SUPPORTED:
		adl_atSendResponse(ADL_AT_UNS, "ADL_RET_ERR_NOT_SUPPORTED\n");
		break;
	case ADL_RET_ERR_SERVICE_LOCKED:
		adl_atSendResponse(ADL_AT_UNS, "ADL_RET_ERR_SERVICE_LOCKED\n");
		break;
	default:
		adl_atSendResponse(ADL_AT_UNS, "default\n");
		break;
	}
}

void SPI_task(void)
{
	adl_busAccess_t AccessConfig = {0,0};
	u8 test = 0xAA;
	adl_busWrite(SpiHandle, &AccessConfig, 1, &test);
}

void main_task(void)
{
	initSPI();
	mainTicker = (adl_tmr_t*) adl_tmrSubscribe (TRUE, 10,
			ADL_TMR_TYPE_100MS, (adl_tmrHandler_t) SPI_task);
}

The output: ADL_RET_ERR_BAD_HDL. According to the documentation, this value is returned “if a GPIO required by the provided bus configuration is currently
subscribed by an application.” How could this be? I’m only using one port! What am I doing wrong here?

Similar (unresolved) issue here:

https://forum.sierrawireless.com/t/cant-subscribe-spi-bus-after-use-as-gpio/3537/1

Hiya,

What module are you using? The thoughts below are with regards to the Q2686 and Q2698 modules.

Make sure that the GPIO is

  1. not used by another module - eg not a GPIO used by the UART as (in the case of the UART) ALL 9 GPIO are used by the UART module even if you’re only using UART 5 wire or 2 wire mode. You can how the UARTs are assigned by using AT+WMFM. If the uart is ‘open’ that means it is under control of the firmware, and all the GPIO are assigned to the UART hardware.
  2. If the module is Q2686/Q2687 make sure that the GPIO keyboard functionality is not enabled - see AT+WHCNF
  3. If the GPIO is otherwise used by the Firmware - see AT+WIOM

All that said, from your code you are trying to use GPIO20 (hardware pin 48) as your CS - and my reading of the Q2686 and Q2698 PTS documents indicate that this GPIO is not shared between modules.

I’m also not sure if your Clock speed of 0 is correct - although the ADL guide says that it is. I use the following:

#define PCLK 13000					// Max Clock Freq in kHz)
#define SPICLK 6000					// desired clock freq (in kHz)

// SPI bus subscription data
// SPI2
const adl_busSPISettings_t SpiLcdConfig =
{
        (PCLK/(1 + SPICLK)),          	// SPI bus speed (should be 6000kHz)
        ADL_BUS_SPI_CLK_MODE_3,         // SPI Bus mode (CLK idle HI, Data read on Rising Edge)
        ADL_BUS_SPI_ADDR_CS_GPIO,       // Set up chip select pin (use GPIO pin)
        ADL_BUS_SPI_CS_POL_LOW,         // chip select Active state (LOW)
        ADL_BUS_SPI_MSB_FIRST,          // data are sent MSB first
        ADL_IO_GPIO | 35,               // GPIO to use for CS - not applicable for CS_HARD
        ADL_BUS_SPI_LOAD_UNUSED,        // LOAD Signal
        ADL_BUS_SPI_DATA_BIDIR,         // DataLinesConf
        ADL_BUS_SPI_MASTER_MODE,        // Master Node
        ADL_BUS_SPI_BUSY_UNUSED         // Busy Signal
};

// BUS Handle
s32 SpiLcdHandle = ERROR;

s32 spiOpen( void )
{
	u32 maxClock;
    // subscribe to SPI bus (SPI2 for LCD)

	adl_regGetHWInteger("spi_02_Master_MaxFreqClock", (s32 *)&maxClock);
    TRACE (( 1, "spiInit:  max SPI Clock [%d] ", maxClock ));

    SpiLcdHandle = adl_busSubscribe( ADL_BUS_ID_SPI, 2, (adl_busSettings_u *) &SpiLcdConfig);

    TRACE (( 1, "spiInit:  SpiLcdHandle [%d] ", SpiLcdHandle ));

	return SpiLcdHandle;
}

to set up to talk to a SPI LCD on a Q2686 module.

Just out of interest, can you use GPIO31 (pin 22) as your CS line?

Let us all know how you get on.

ciao, Dave