Home
JAQForum Ver 24.01
Log In or Join  
Active Topics
Local Time 11:07 27 Apr 2026 Privacy Policy
Jump to

Notice. New forum software under development. It's going to miss a few functions and look a bit ugly for a while, but I'm working on it full time now as the old forum was too unstable. Couple days, all good. If you notice any issues, please contact me.

Forum Index : Microcontroller and PC projects : Memory share with other devices

Author Message
fred777
Regular Member

Joined: 01/07/2021
Location: United Kingdom
Posts: 70
Posted: 08:07am 25 Apr 2026
Copy link to clipboard 
Print this post

Hi there,
would it be possible to feed parallel data to a pico running
Memory share client from a non-pico device?
For instance feeding external pixel data into the frame buffer?
 
matherp
Guru

Joined: 11/12/2012
Location: United Kingdom
Posts: 11247
Posted: 08:40am 25 Apr 2026
Copy link to clipboard 
Print this post

In theory  - yes. You will need to read into Memory.c on github to understand the synchronisation protocol needed to start the transfer. Briefly it works like this:
  Quote  Host-Side Synchronisation Protocol
Phase 1 — Clean state (share_prepare_start)
Before anything else the host:

Disables and restarts the PIO state machine, clears its FIFOs
Aborts both DMA channels and waits for the abort to complete
Reinitialises all data pins and the clock pin as plain SIO GPIO inputs with no pulls
This guarantees a known idle bus regardless of any previous share session.

Phase 2 — PIO program and DMA wired up (but not started)
The host builds a 2-instruction PIO TX program in RAM:


instruction 0:  out  pins, <width>   side 0    ← push data nibble/byte, clock LOW
instruction 1:  nop                  side 1    ← hold, clock HIGH
It wraps back to instruction 0 continuously.

Two DMA channels are configured:

Data channel: reads 32-bit words from the MMBasic shared memory block → PIO TX FIFO, paced by the PIO DREQ, transfers count/4 words, then chains to the control channel.
Control channel: resets the data channel's read address back to the start of the block and retriggers it — creating a perpetual loop. Neither channel is started yet.
Phase 3 — Handshake sync (share_host_sync)
This is the rendezvous with the client. All done with plain GPIO (no PIO), so it can block indefinitely and is user-abortable.

Step Host action
1 Set clock pin as output, drive it LOW
2 Set lower half of data pins as outputs, drive the host pattern: 0101 (8-bit) or 01 (4-bit)
3 Set upper half of data pins as inputs
4 Spin in share_wait_loop() reading the upper pins until the client's complementary pattern appears: 1010 / 10
5 Once the client pattern is seen, hold for 1 ms so the client also has time to read the host pattern, then return
The client does the mirror image: it drives the upper half, reads the lower half, and waits for 0101/01. The two sides unblock each other simultaneously.

Phase 4 — Post-sync wait (5 ms)
After returning from sync the host waits 5 ms before touching the pins again. During this window:

The clock pin is still a GPIO output held LOW (SIO function).
The client is switching its pins from SIO mode into PIO receive mode and arming its wait 1 gpio CLK instruction.
The client's PIO will block on "wait for clock HIGH", so the transition is safe as long as the host doesn't release the clock before the client is ready — the 5 ms margin covers this.

Phase 5 — Pin handover to PIO

data pins  → GPIO_FUNC_PIO*, direction = output
clock pin  → GPIO_FUNC_PIO*, direction = output
The data pins are handed to PIO while the clock is still LOW. The SM is then cleared, restarted, and enabled.

The first instruction the SM executes is out pins side 0, which drives clock LOW and pushes the first data word onto the bus. The client's PIO is waiting for clock HIGH (wait 1 gpio CLK) so it doesn't latch anything until the second instruction (nop side 1) raises the clock.

Phase 6 — DMA triggered, streaming begins

dma_start_channel_mask(1u << SHARE_DMA_CTRL);
The control channel fires immediately, which retriggers the data channel. The data channel starts pumping 32-bit words from the shared memory block into the PIO TX FIFO. PIO pulls words from the FIFO and clocks them out one nibble or byte per clock cycle, looping forever through the block.

Summary timeline

Host:  [prepare clean] [build PIO/DMA] [drive 0101, wait for 1010] [hold 1ms] [wait 5ms] [hand pins to PIO] [start DMA]
        ↑ phase 1          ↑ phase 2         ↑ phase 3                ↓           ↑ phase 4       ↑ phase 5      ↑ phase 6
Client:                                  [drive 1010, wait for 0101] [hold 1ms] [switch to PIO RX] [wait CLK HIGH → latch data]
The key design choice is that the PIO programs contain no startup logic — they are pure streaming state machines. All the "are both sides ready?" negotiation happens in software using plain GPIO, keeping the PIO timing deterministic once streaming starts.
 
fred777
Regular Member

Joined: 01/07/2021
Location: United Kingdom
Posts: 70
Posted: 08:51am 25 Apr 2026
Copy link to clipboard 
Print this post

Thanks for the great explanation!
If I understand this correctly, the clock speed
after the setup is completed doesn’t matter much, right?
Would it matter if the host would only send data
occasionally?
 
matherp
Guru

Joined: 11/12/2012
Location: United Kingdom
Posts: 11247
Posted: 08:54am 25 Apr 2026
Copy link to clipboard 
Print this post

The client runs in a tight DMA/PIO loop waiting on the clock pulses so as long as the host stays in synch it should be OK
 
fred777
Regular Member

Joined: 01/07/2021
Location: United Kingdom
Posts: 70
Posted: 09:10am 25 Apr 2026
Copy link to clipboard 
Print this post

Right, I’ll have a go at that. The idea is to feed
the pixels from some stm mcus with attached camera directly into regions on the picomite’s screen buffer.
And also gaining hdmi output along the way.
 
Print this page


To reply to this topic, you need to log in.

The Back Shed's forum code is written, and hosted, in Australia.
© JAQ Software 2026