Skip to content

drivers: add nRF24L01+ driver - #1083

Open
matpala wants to merge 2 commits into
ZigEmbeddedGroup:mainfrom
matpala:drivers/nrf24l01
Open

matpala wants to merge 2 commits into
ZigEmbeddedGroup:mainfrom
matpala:drivers/nrf24l01

Conversation

@matpala

@matpala matpala commented Oct 9, 2026 •

Copy link
Copy Markdown
Contributor

Adds a polling driver targeting the nRF24L01+ and Si24R1. Part of #1069.

  • Supports concrete device types and the base interfaces through vtables.
  • Uses pipe 0, a shared 5-byte TX/RX address and fixed 1–32-byte payloads at 1 Mbps, with 2-byte CRC, auto-ack and up to 15 retransmissions. Preserves TX power bits and validates channel and payload size before hardware access.
  • Provides listening controls, blocking acknowledged sends and polled receives. Send and receive buffers must match the configured payload size.
  • Unit tests check command bytes, final CE states, accumulated delays, validation and send/receive outcomes.

Requires mode-0 SPI with CS controlled by connect/disconnect, writev and writev_then_readv, plus CE and clock devices. Call apply after power-on reset and stop listening before sending.

Output parameters work around AVR issue zig#37099 in Zig 0.17.0; the fix is for 0.17.1. STATUS is read with R_REGISTER. This PR does not depend on #1077; using full-duplex transfers would require that API to merge, adapter support and a driver update.

Tested on an Emakefun RF-Nano V3.0: the rf-nano-v3_spi_nrf24 example now uses the driver through minimal local adapters (SPI with CS, CE and a busy-wait clock). With no second radio, each send reports [no ACK] (error.MaxRetries). ATmega328P driver adapters with a Timer0 clock, and a two-radio send/receive example, are planned next.

@Grazfather

Copy link
Copy Markdown
Collaborator

Can you adapt your example to use this driiver?

@matpala

matpala commented Oct 11, 2026

Copy link
Copy Markdown
Contributor Author

Done: spi_nrf24 now uses the driver (zero-cost mode) with small local adapters for the SPI, CE and a busy-wait clock, since the port has no timer clock or drivers.zig yet. Tested on the RF-Nano V3: with a single radio each key press reports [no ACK], as expected.

@matpala
matpala marked this pull request as ready for review October 11, 2026 05:08
Comment on lines +370 to +386
&.{ 0x20, 0x0C }, // CONFIG: power down
&.{ 0x21, 0x01 }, // EN_AA: pipe 0
&.{ 0x22, 0x01 }, // EN_RXADDR: pipe 0
&.{ 0x23, 0x03 }, // SETUP_AW: 5 bytes
&.{ 0x24, 0x5F }, // SETUP_RETR: 1.5 ms, 15 retransmits
&.{ 0x25, 76 }, // RF_CH
&.{0x06}, // read RF_SETUP
&.{ 0x26, 0x07 }, // RF_SETUP: 1 Mbps, TX power kept
&.{ 0x2A, 1, 2, 3, 4, 5 }, // RX_ADDR_P0
&.{ 0x30, 1, 2, 3, 4, 5 }, // TX_ADDR
&.{ 0x31, 32 }, // RX_PW_P0
&.{ 0x3C, 0x00 }, // DYNPD
&.{ 0x3D, 0x00 }, // FEATURE
&.{ 0x27, 0x70 }, // STATUS: clear RX_DR, TX_DS and MAX_RT
&.{0xE1}, // FLUSH_TX
&.{0xE2}, // FLUSH_RX
&.{ 0x20, 0x0E }, // CONFIG: 2-byte CRC, PWR_UP, PRIM_RX=0

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

How are these determined?

@matpala matpala Oct 12, 2026 •

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

These are manually encoded expected bytes for this configuration, using the nRF24L01+ Product Specification v1.0 (§8.3.1, Table 20; §9.1, Table 28). Register writes use 0x20 | address; 0x06 reads RF_SETUP, and 0xE1/0xE2 flush the FIFOs. The data reflects the configuration and test inputs: CONFIG 0x0E enables two-byte CRC and power, RX_PW_P0 uses the default 32-byte payload, and RF_SETUP becomes 0x07 from the simulated 0x0F readback. The expected array uses literals instead of the driver's encoding constants, so encoding errors can fail the test.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The expected array uses literals instead of the driver's encoding constants, so encoding errors can fail the test.

I don't get what you mean by this, explain

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I think he/she means that it's not written in terms of the constants and such because otherwise the test would basically be testing something like assert(send command STATUS sends command STATUS)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Yes, exactly, thanks @Grazfather. For example, if command.w_register were accidentally set to 0x40 instead of 0x20, the driver would send 0x40 for a CONFIG write. If the expected bytes reused that constant, they would also contain 0x40, so the comparison would pass despite the bug. Keeping the expected byte as 0x20, taken from the datasheet, makes that comparison fail and catches the mistake.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants