-
Notifications
You must be signed in to change notification settings - Fork 225
Software PWM Work #24
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: master
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 |
---|---|---|
@@ -0,0 +1,48 @@ | ||
/* | ||
|
||
A Software Based PWM example by @Ronin11, using the go-rpio library | ||
|
||
Toggles a LED on physical pin 10 | ||
Connect a LED with resistor from pin 10 to ground. | ||
|
||
*/ | ||
|
||
package main | ||
|
||
import ( | ||
"fmt" | ||
"os" | ||
"time" | ||
|
||
"github.com/Ronin11/go-rpio" | ||
) | ||
|
||
const pin = rpio.Pin(10) | ||
|
||
func main() { | ||
|
||
if err := rpio.Open(); err != nil { | ||
fmt.Println(err) | ||
os.Exit(1) | ||
} | ||
|
||
// Unmap gpio memory when done | ||
defer rpio.Close() | ||
|
||
//Creates the PWM Signal running on the pin, at 2KHz, with a 0% PWM cycle. | ||
pwm := rpio.CreateSofwarePWM(pin, 2000, 0, 32) | ||
|
||
pwm.Start() | ||
defer pwm.Stop() | ||
// five times smoothly fade in and out | ||
for i := 0; i < 5; i++ { | ||
for i := uint32(0); i < 32; i++ { // increasing brightness | ||
pwm.SetDutyCycle(i, 32) | ||
time.Sleep(time.Second/32) | ||
} | ||
for i := uint32(32); i > 0; i-- { // decreasing brightness | ||
pwm.SetDutyCycle(i, 32) | ||
time.Sleep(time.Second/32) | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -79,6 +79,27 @@ type State uint8 | |
type Pull uint8 | ||
type Edge uint8 | ||
|
||
type PwmStatus uint8 | ||
const ( | ||
STOPPED PwmStatus = 0 | ||
RUNNING PwmStatus = 1 | ||
) | ||
|
||
type PwmState uint8 | ||
const ( | ||
OFF PwmState = 0 | ||
ON PwmState = 1 | ||
) | ||
|
||
type SoftwarePWM struct { | ||
pin Pin | ||
freq uint32 | ||
dutyLen uint32 | ||
cycleLen uint32 | ||
status PwmStatus | ||
state PwmState | ||
} | ||
|
||
// Memory offsets for gpio, see the spec for more details | ||
const ( | ||
bcm2835Base = 0x20000000 | ||
|
@@ -547,6 +568,58 @@ func StartPwm() { | |
pwmMem[pwmCtlReg] = pwmMem[pwmCtlReg] | pwen<<8 | pwen | ||
} | ||
|
||
//Create a Software PWM struct | ||
func CreateSofwarePWM(pin Pin, freq uint32, dutyLen uint32, cycleLen uint32) *SoftwarePWM{ | ||
//Set pin as Output | ||
pin.Output() | ||
return &SoftwarePWM{pin: pin, freq: freq, dutyLen: dutyLen, cycleLen: cycleLen} | ||
} | ||
|
||
//Sets the duty cycle for the software PWM | ||
func (swPwm *SoftwarePWM) SetDutyCycle(dutyLen uint32, cycleLen uint32){ | ||
swPwm.dutyLen = dutyLen | ||
swPwm.cycleLen = cycleLen | ||
} | ||
|
||
//Sets the frequency of the software PWM | ||
func (swPwm *SoftwarePWM) SetFreq(freq uint32){ | ||
swPwm.freq = freq | ||
} | ||
|
||
//Starts the software PWM | ||
func (swPwm *SoftwarePWM) Start(){ | ||
swPwm.status = RUNNING | ||
swPwm.pwmLoop() | ||
} | ||
|
||
//Stops the software PWM | ||
func (swPwm *SoftwarePWM) Stop(){ | ||
swPwm.status = STOPPED | ||
swPwm.pin.Write(Low) | ||
} | ||
|
||
|
||
//Internal PWM execution loop | ||
func (swPwm *SoftwarePWM) pwmLoop(){ | ||
go func(){ | ||
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. No need to use anonymous function, you can use |
||
var sleepInterval time.Duration | ||
for swPwm.status == RUNNING { | ||
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. There is no need for ON/OFF state if you use something like this:
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. Or better break using select and channel as I mentioned before.
I would also use |
||
//sleepInterval is the basic unit of time between pwm 'ticks' | ||
sleepInterval = time.Second / time.Duration(swPwm.freq) | ||
if swPwm.state == OFF { | ||
swPwm.pin.Write(High) | ||
swPwm.state = ON | ||
sleepInterval = sleepInterval * time.Duration(swPwm.dutyLen) | ||
} else { | ||
swPwm.pin.Write(Low) | ||
swPwm.state = OFF | ||
sleepInterval = sleepInterval * time.Duration(swPwm.cycleLen - swPwm.dutyLen) | ||
} | ||
time.Sleep(sleepInterval) | ||
} | ||
}() | ||
} | ||
|
||
// Open and memory map GPIO memory range from /dev/mem . | ||
// Some reflection magic is used to convert it to a unsafe []uint32 pointer | ||
func Open() (err error) { | ||
|
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 go way to stop the loop might be to use "terminating" channel. Using status value like this is not thread safe.