Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

drivers: spi: Add support for half-duplex (3-wire) SPI #69634

Merged

Conversation

ThreeEights
Copy link
Contributor

Add support for half-duplex (3-wire) SPI operation using the Raspberry Pi Pico PIO. To allow control of the size of the driver, including half-duplex support is optional, under the control of Kconfig options.

The original PIO source code is also included as a reference.

@zephyrbot zephyrbot added area: SPI SPI bus area: Devicetree Binding PR modifies or adds a Device Tree binding platform: Raspberry Pi Pico Raspberry Pi Pico (RPi Pico) labels Feb 29, 2024
@ThreeEights ThreeEights force-pushed the rpi-pico-half-duplex-spi branch 2 times, most recently from 3e7d204 to 2fc7abb Compare March 1, 2024 20:11
@ThreeEights
Copy link
Contributor Author

Drat - the tx/rx counts in the 3-wire logic were wrong. Corrected.

@@ -0,0 +1,78 @@
; Copyright (c) 2023 Stephen Boylan <stephen.boylan@beechwoods.com>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this file needed?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Strictly speaking, no; at this time, this file is essentially documentation. We went back and forth on including this file. This is the original source for generating the embedded binary PIO code, but can't be used directly in builds without the ability to use pioasm in the build process. If it's the consensus of reviewers that it doesn't make sense to include this file now, I'll remove it.

Copy link
Member

@soburi soburi Mar 5, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file should be deleted, as it is not possible to include unnecessary files other than documents.
It seems that the code is already embedded in the C source as a comment, but it might be better to write it in the form of the original code here.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ThreeEights
Please remove this file.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed.

drivers/spi/Kconfig.rpi_pico Outdated Show resolved Hide resolved
drivers/spi/spi_rpi_pico_pio.c Outdated Show resolved Hide resolved
Comment on lines 547 to 564
#if defined(CONFIG_SPI_RPI_PICO_PIO_32_BIT)
case 4: {
if (txbuf) {
txrx = ((uint32_t *)txbuf)[data->tx_count];
}
spi_pico_pio_sm_put32(data->pio, data->pio_sm, txrx);
data->tx_count += 4;
} break;
#endif /* CONFIG_SPI_RPI_PICO_PIO_32_BIT */

#if defined(CONFIG_SPI_RPI_PICO_PIO_16_BIT)
case 2: {
if (txbuf) {
txrx = ((uint16_t *)txbuf)[data->tx_count];
}
spi_pico_pio_sm_put16(data->pio, data->pio_sm, txrx);
data->tx_count += 2;
} break;
#endif /* CONFIG_SPI_RPI_PICO_PIO_16_BIT */

#if defined(CONFIG_SPI_RPI_PICO_PIO_8_BIT)
case 1: {
if (txbuf) {
txrx = ((uint8_t *)txbuf)[data->tx_count];
}
spi_pico_pio_sm_put8(data->pio, data->pio_sm, txrx);
data->tx_count++;
} break;
#endif /*CONFIG_SPI_RPI_PICO_PIO_8_BIT*/
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is just a matter of style and preference, but there are ifdefs all over the place, so it would be nice to see them put together. For example, how about changing the function to something like this?

static inline int spi_pico_pio_sm_put(PIO pio, uint sm, void *dataptr, size_t bits)
{
        switch(bits) {
		case 4:
			*((io_rw_32 *)&pio->txf[sm]) = *(uint32_t*)dataptr;
			return 4;
		case 2:
			*((io_rw_8 *)&pio->txf[sm]) = *(uint16_t*)dataptr;
			return 2;
		case 1:
			*((io_rw_8 *)&pio->txf[sm]) = *(uint8_t*)dataptr;
			return 1;
		default:
			return 0;
        }
}

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unless one wants to save some ROM bytes, in this case the defines are useful. (unless, again, these defines disappear and become DTS properties)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Condensing the ..._put and ..._get code, as @soburi suggested, is a good idea. That makes the source code a lot shorter and cleaner. I'll try to get that to work.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unfortunately, condensing the get and set functions won't work. The logic is different in the 4-wire and 3-wire cases, and it's necessary to split reading the data from the tx buffer and writing to the send FIFO: if there's data to send, it needs to use the content from the txbuf, but if there's no txbuf data, 0 has to be sent in order to clock the receive data. Similarly, the data in the receive FIFO has to be read out, even if there's no rxbuf, in order to sync the send and receive cycle with the spi_context.

The only changes I can see that might make sense would be to move the FIFO operations out of the get and put functions, eliminating those, which can reduce the number of places where compile-time checks are needed for the 2 and 4 byte transactions.

Would it make sense to remove those Kconfig options? Is that modest increase in overhead for the most common 8-bit case acceptable?

drivers/spi/spi_rpi_pico_pio.c Show resolved Hide resolved
drivers/spi/Kconfig.rpi_pico Outdated Show resolved Hide resolved
@ThreeEights
Copy link
Contributor Author

@soburi, @tbursztyka, @yonsch - Can you please take a look at the latest changes and see if the issues are resolved? Thanks!

@Ablu
Copy link

Ablu commented Apr 5, 2024

@ThreeEights: Is this the last gap that is needed to use bluetooth/wifi on the Pico W? Or is there further glue code between the CYW43xxx driver and this required?

Do you happen to have device-trees for enabling the cyw43439 around? Then I would be happy to give it a try :).

@ThreeEights
Copy link
Contributor Author

@Ablu - Alas, no: The current Infineon WiFi driver for the CYW43439 does not have SPI support. If you're interested, you can view my latest attempt (as of yesterday!) on my fork:
https://github.com/ThreeEights/zephyr on branch airoc-wifi-spi

Add support for half-duplex (3-wire) SPI operation using the Raspberry
Pi Pico PIO.  To allow control of the size of the driver, including
half-duplex support is optional, under the control of Kconfig options.

The original PIO source code is also included as a reference.

Corrected 3-wire tx/rx counts.

Enable half-duplex code based on DTS configuration

Replace runtime checks with static BUILD_ASSERT()

Remove too-fussy Kconfig options

Removed PIO source per review request

Signed-off-by: Steve Boylan <stephen.boylan@beechwoods.com>
@soburi
Copy link
Member

soburi commented Apr 10, 2024

@tbursztyka
May we have your opinion?

@ThreeEights
Copy link
Contributor Author

@yonsch - Could you please take a look at this pull request? Thanks.

@carlescufi carlescufi merged commit 5b72665 into zephyrproject-rtos:main Apr 18, 2024
21 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area: Devicetree Binding PR modifies or adds a Device Tree binding area: SPI SPI bus platform: Raspberry Pi Pico Raspberry Pi Pico (RPi Pico)
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

6 participants