-
Notifications
You must be signed in to change notification settings - Fork 1
feature: add PWM pin transmitter to the Morse code example #11
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
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,4 +1,4 @@ | ||
| //go:build !si5351 && !featherwing | ||
| //go:build !si5351 && !featherwing && !pwm | ||
|
|
||
| package main | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,107 @@ | ||
| //go:build pwm | ||
|
|
||
| package main | ||
|
|
||
| import ( | ||
| "machine" | ||
| "time" | ||
|
|
||
| "github.com/chewxy/math32" | ||
| "tinygo.org/x/wireless/morse" | ||
| ) | ||
|
|
||
| var ( | ||
| pwm = machine.PWM0 | ||
| pin = machine.GPIO16 | ||
| sampleRate float32 = 11_025.0 // suitable for AM radio | ||
| ) | ||
|
|
||
| func initRadio() *morse.Morse { | ||
| err := pwm.Configure(machine.PWMConfig{ | ||
| Period: 1854, // 1854 ns, approx 540 kHz | ||
| }) | ||
|
|
||
| transmitChannel, err := pwm.Channel(pin) | ||
| if err != nil { | ||
| println("failed to configure channel") | ||
| return nil | ||
| } | ||
|
|
||
| samples := make([]uint32, 512) | ||
| generateSineWave(samples, 440, sampleRate) | ||
|
|
||
| m := morse.NewMorse(&PinRadio{transmitChannel: transmitChannel, samples: samples}, 540_000, 5) | ||
| m.Configure() | ||
|
|
||
| return m | ||
| } | ||
|
|
||
| // PinRadio implements a simple radio using PWM on a GPIO pin. | ||
| // | ||
| // It uses PWM to generate an audio tone that is transmitted using amplitude | ||
| // modulation (AM). | ||
| // | ||
| // NOTE: You should use a low-pass filter connected to the output pin to get | ||
| // a cleaner signal and avoid harmonics that will cause interference for both | ||
| // yourself and others. | ||
| // | ||
| // See https://github.com/tudbut/picoAM for the original inspiration. | ||
| type PinRadio struct { | ||
| transmitChannel uint8 | ||
| samples []uint32 | ||
| stopChan chan struct{} | ||
| } | ||
|
|
||
| func (r *PinRadio) Transmit(freq uint64) error { | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. frequency in morse constructor (540_000) is ignored, and also the frequency argument to |
||
| r.stop() | ||
| r.stopChan = make(chan struct{}) | ||
|
|
||
| go func(stop <-chan struct{}) { | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe instead spinning a goroutine on each Transmit call, just spin one goroutine on |
||
| for { | ||
| select { | ||
| case <-stop: | ||
| return | ||
| default: | ||
| } | ||
| for _, v := range r.samples { | ||
| pwm.Set(r.transmitChannel, v) | ||
| time.Sleep(time.Duration(1e9/sampleRate) * time.Nanosecond) | ||
| } | ||
| } | ||
| }(r.stopChan) | ||
|
|
||
| return nil | ||
| } | ||
|
|
||
| func (r *PinRadio) Standby() error { | ||
| r.stop() | ||
| pwm.Set(r.transmitChannel, 0) | ||
|
|
||
| return nil | ||
| } | ||
|
|
||
| func (r *PinRadio) Close() error { | ||
| r.stop() | ||
| pwm.Set(r.transmitChannel, 0) | ||
|
|
||
| return nil | ||
| } | ||
|
|
||
| func (r *PinRadio) stop() { | ||
| if r.stopChan != nil { | ||
| close(r.stopChan) | ||
| r.stopChan = nil | ||
| } | ||
| } | ||
|
|
||
| func generateSineWave(samples []uint32, freq uint64, sampleRate float32) { | ||
| top := pwm.Top() | ||
| min := top / 4 | ||
| max := top | ||
|
|
||
| for i := range samples { | ||
| v := math32.Sin(2.0 * math32.Pi * float32(i) * float32(freq) / sampleRate) | ||
| v = (v + 1.0) / 2.0 // shift to [0, 1] | ||
| samples[i] = uint32(float32(min) + v*float32(max-min)) | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think morse protocol should not be configured with carrier frequency (540kHz) but instead with frequency that is modulated by digital signal (440Hz in this case) like it is the case with other radio types.