I've got a SPI slave device connected to my Laird BL652 (based on the nRF52832). The slave requires the following transaction on the SPI bus:
Note that the total transaction size is 16 bits.
The SPI section of the module's dts file looks like this:
&spi0 { compatible = "nordic,nrf-spi"; /* Cannot be used together with i2c0. */ /* status = "okay"; */ cs-gpios = <&gpio0 22 GPIO_ACTIVE_LOW>; pinctrl-0 = <&spi0_default>; pinctrl-1 = <&spi0_sleep>; pinctrl-names = "default", "sleep"; };
And I've added an overlay that looks like this in order to enable the device and generate the CS signal on GPIO 18.
&spi0 { cs-gpios = <&gpio0 18 GPIO_ACTIVE_LOW>; status = "okay"; };
My test code to use the SPI looks like this:
const struct spi_dt_spec spi_spec = { .bus = DEVICE_DT_GET(DT_NODELABEL(spi0)) }; if( spi_spec.bus == NULL ) { printk("SPI not initialized.\n"); return SPI_NOT_INITIALIZED; } else if( ! device_is_ready(spi_spec.bus) ) { printk("SPI not ready.\n"); return SPI_NOT_READY; } uint8_t spi_bytes[2] = {0}; const struct spi_buf my_spi_buf[1] = {// Buffer to hold one set of SPI data [0].buf = spi_bytes,// The byte array to send [0].len = 2// Number of bytes in buffer }; const struct spi_buf_set tx_buff = { .buffers = my_spi_buf, .count = 1 }; int spi_write_return = spi_write_dt(&spi_spec,&tx_buff); if( spi_write_return >= 0 ) { return MESSAGE_OK; } else { printk("Error number %d in SPI write.\n" , spi_write_return ); return SPI_WRITE_ERROR; }
When I run the code, I get the following error message: <err> spi_nrfx_spi: configure: Word sizes other than 8 bits are not supported
The error number returned by spi_write_dt is -22.
Now, I'm not setting anything in the "operation" field of the spi_spec structure and I guess I need to. Here's the code from spi.h that describes all the various bit fields in the int16_t operation word.
/** * @brief SPI controller configuration structure * * @param frequency is the bus frequency in Hertz * @param operation is a bit field with the following parts: * * operational mode [ 0 ] - master or slave. * mode [ 1 : 3 ] - Polarity, phase and loop mode. * transfer [ 4 ] - LSB or MSB first. * word_size [ 5 : 10 ] - Size of a data frame in bits. * duplex [ 11 ] - full/half duplex. * cs_hold [ 12 ] - Hold on the CS line if possible. * lock_on [ 13 ] - Keep resource locked for the caller. * cs_active_high [ 14 ] - Active high CS logic. * format [ 15 ] - Motorola or TI frame format (optional). * if @kconfig{CONFIG_SPI_EXTENDED_MODES} is defined: * lines [ 16 : 17 ] - MISO lines: Single/Dual/Quad/Octal. * reserved [ 18 : 31 ] - reserved for future use. * @param slave is the slave number from 0 to host controller slave limit. * @param cs is a valid pointer on a struct spi_cs_control is CS line is * emulated through a gpio line, or NULL otherwise. * @warning Most drivers use pointer comparison to determine whether a * passed configuration is different from one used in a previous * transaction. Changes to fields in the structure may not be * detected. */ struct spi_config { uint32_t frequency; #if defined(CONFIG_SPI_EXTENDED_MODES) uint32_t operation; uint16_t slave; uint16_t _unused; #else uint16_t operation; uint16_t slave; #endif /* CONFIG_SPI_EXTENDED_MODES */ const struct spi_cs_control *cs; };
I would have hoped many of operation bits are set by default but I guess not. So I have the following questions:
- Given the SPI transaction as I showed it at the top of this question, what should be the values of the various operation bits.
- Is there a C bit-field data structure (as I created in the code fragment below) to make it easier to manage the fields?
As an experiment, I created the following code to set the bit fields in the operation word. I'm not sure I got them all correct but it's a start. I'm also setting the frequency to 1MHz.
union op_combo { struct { uint16_t op_mode: 1; // [0] - master or slave. uint16_t mode: 3; // [ 1 : 3 ] - Polarity, phase and loop mode. uint16_t transfer: 1; // [ 4 ] - LSB or MSB first. uint16_t word_size: 6; // [ 5 : 10 ] - Size of a data frame in bits. uint16_t duplex: 1; // [ 11 ] - full/half duplex. uint16_t cs_hold: 1; // [ 12 ] - Hold on the CS line if possible. uint16_t lock_on: 1; // [ 13 ] - Keep resource locked for the caller. uint16_t cs_active_high: 1; // [ 14 ] - Active high CS logic. uint16_t format: 1; // [ 15 ] - Motorola or TI frame format (optional). } fields; uint16_t word; }; const union op_combo operation = { .fields.op_mode = 0, .fields.mode = 0, .fields.transfer = 0, .fields.word_size = 8, .fields.duplex = 0, .fields.cs_hold = 0, .fields.lock_on = 0, .fields.cs_active_high = 0, .fields.format = 1 }; printk("op = 0x%x\n",operation.word); const struct spi_dt_spec spi_spec = { .bus = DEVICE_DT_GET(DT_NODELABEL(spi0)), .config.operation = operation.word, .config.frequency = 1000000, .config.slave = 0 };
Now I'm getting the following runtime error: <err> spi_nrfx_spi: spi_context_wait_for_completion: Timeout waiting for transfer complete
And error code -116 returned from spi_write_dt.
Note that I'm not seeing anything coming out of the SPI bus so I'm guessing the timeout is set to 0 somewhere and the driver is timing out immediately.
From what I understand, the driver is supposed to calculate the timeout based on the transfer size and clock rate, but there appear to be some bugs associated with this, namely bugs #53957 and #53965.
- I'm using toolchain version 2.3.0. Are these bugs fixed in that version? If not, is there a patch I can apply?
Thanks,
Bret