Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings
This repository was archived by the owner on Dec 8, 2025. It is now read-only.

Bitbanging on the ESP32 #577

Answered by pelikhan
ertw asked this question in Q&A
Jul 21, 2023 · 4 comments · 6 replies
Discussion options

Hello, I'm wondering if I should be able to write digital IO at high speeds on the ESP32. I'm trying to drive a stepper, and am using 4 output pins to generate the waveform. I need to switch at 2ms intervals for this, but it isn't working. When I look at the output on a scope, I see that the timing is actually between 2-5ms. Even looping at 50ms intervals still isn't perfect. At around 100ms intervals, timing looks fine.

I ran my code on the adorable little Seeed Studio MCU, and also on the Rust devboard to rule out a bad device. They both performed about the same.

I'll include the full code below. Any ideas on what could be causing the issue here? Is there some way to guarantee realtime execution?

import * as ds from "@devicescript/core"
import { GPIOMode } from "@devicescript/core"
import "@devicescript/gpio"
import { pins } from "@dsboard/seeed_xiao_esp32c3"
import { schedule } from '@devicescript/runtime'
const minStepInterval = 2
const p0 = pins.A0_D0
const p1 = pins.A1_D1
const p2 = pins.A2_D2
const p3 = pins.A3_D3
await p0.setMode(GPIOMode.Output)
await p1.setMode(GPIOMode.Output)
await p2.setMode(GPIOMode.Output)
await p3.setMode(GPIOMode.Output)
const oneStep = async (step: number) => {
 switch (step) {
 case 0:
 await p0.write(1)
 await p1.write(0)
 await p2.write(0)
 await p3.write(0)
 break;
 case 1:
 await p0.write(0)
 await p1.write(1)
 await p2.write(0)
 await p3.write(0)
 break;
 case 2:
 await p0.write(0)
 await p1.write(0)
 await p2.write(1)
 await p3.write(0)
 break;
 case 3:
 await p0.write(0)
 await p1.write(0)
 await p2.write(0)
 await p3.write(1)
 break;
 default:
 break;
 }
}
schedule(async ({ counter, elapsed, delta }) => {
 await oneStep(counter % 4)
}, { interval: minStepInterval })
You must be logged in to vote

Unfotunately these will suffer from the same timing issues.

Replies: 4 comments 6 replies

Comment options

Unfortunately, DeviceScript is not designed for real-time bit-banging :/

Would PWM work for you (assuming you can turn it on/off with a few ms accuracy)? We currently only expose it as services implemented in C (lightbulb, buzzer, motor, servo) but could probably expose it directly?

You must be logged in to vote
0 replies
Comment options

You must be logged in to vote
2 replies
Comment options

Unfotunately these will suffer from the same timing issues.

Answer selected by ertw
Comment options

Comment options

Thanks all! For my case, I'll be able to move to a component that uses SPI rather than trying to bang it out manually. I also reread the documentation and realized that GC is going to cause pauses anyway, so no way to do realtime.

You must be logged in to vote
4 replies
Comment options

We should add this in the runtime docs or the faq.

"Can I do (real) time dependent bit banging..?"

Comment options

added warning in 41a14a8

do we have a FAQ?

Comment options

we don't seem to have one yet.

Comment options

Your comment looks good enough imo.

Comment options

@ertw keep us posted on your progress!

You must be logged in to vote
0 replies
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Category
Q&A
Labels
None yet

AltStyle によって変換されたページ (->オリジナル) /