Closed wbourne0 closed 3 years ago
The scheduler is turned off by default on AVR, as there really isn't that much memory available. You can enable the scheduler with -scheduler=tasks
.
Also note, that your for loop will repeatedly print the same time, without letting the goroutine run. You need to have something pause in the loop so that other things can be run.
println(now.String())
See https://github.com/tinygo-org/tinygo/issues/953.
You can still do time.Sub
to get a duration, and then divide by time.Millisecond
.
Oh. But no matter what the time (in unix) is always 0. If i print time.Now().Unix()
its always giving me 0. Is there a way to directly call millis
from arduino.h
or is that impossible?
Also i didnt notice that in the docs (note that its probably there) maybe you could make it more apparent? Like in the machine docs for it
package main
import (
"time"
)
func main() {
for {
now := time.Now()
println(now.Unix())
}
}
Output:
0
0
0
0
0
...
Edit:
Not as i said above, I know arduino doesnt have any real time support. It would be nice to have some sort of wrapper for arduino's millis()
though.
see https://github.com/tinygo-org/tinygo/issues/952
this is something which we have been wanting to fix (time.Sleep output only counts up while sleeping), but nobody has stepped up to implement that yet
It is not likely that we will ever be compatible with Arduino.h
on most platforms, since we use interrupts which arduino also tries to use.
If you would like to work on better timer support, we would certainly appreciate any contribution. It should not be all too difficult, now that we have proper interrupt support for AVR.
I'd be fine with that, if i have the time. Would be nice to have some pulseIn and pulseOut functions aswell, might look at those also.
One issue with proper time support is that it will interfere with the PWM (all available timers are also used for PWM). I'm not sure what the best solution is but once PWM support is improved, I would argue it may be a better idea to put it in a library.
The way Arduino "fixes" it is by making the PWM harder to control (and thus making it harder to use with servos etc.).
Another issue to add to the list: I cant read input from any pin. Arduino code:
package main
import (
"machine"
)
func main() {
in := machine.ADC{Pin: machine.A0}
in.Configure()
for {
println(in.Get())
}
}
As I just have my 3.5 volt pin connected directly to A0 (Wanted to guarantee results), i always get ~680-682.
With the go code however:
package main
import (
"machine"
)
func main() {
in := machine.ADC{Pin: machine.A0}
in.Configure()
for {
println(in.Get())
}
}
I only get 0s, with the same setup used with the arduino code (just a cable connected 3.5v to A0) Edit: Just to clarify, I get the same result with any pin.
I point you to the example here: https://github.com/tinygo-org/tinygo/blob/master/src/examples/adc/adc.go
Notice that your code is missing machine.InitADC()
.
Hope that helps!
Oops. Should have noticed that. I noticed that gourotines dont run even with -scheduler=tasks. Actually, with -scheduler=tasks, nothing at all runs, main doesnt seem to be called, even with a 1 line print statement. I was able to get it to partially work with courotines, but its still buggy:
package main
import (
"time"
"tinygo/machine"
)
func timedOutput(pin machine.Pin) {
for {
time.Sleep(5 * time.Millisecond)
pin.High()
time.Sleep(5 * time.Millisecond)
pin.Low()
}
}
func main() {
out := machine.D46
in := machine.D48
output := machine.PinConfig{Mode: machine.PinOutput}
input := machine.PinConfig{Mode: machine.PinInput}
out.Configure(output)
in.Configure(input)
go timedOutput(out)
for {
if in.Get() {
println("Recieved signal")
} else {
println("Haven't gotten a signal.")
}
// This nexer exits. Instead, timedOutput runs forever.
time.Sleep(1 * time.Second)
}
}
There is a reason goroutines are disabled by default on the Uno: they require a lot of RAM. I don't know what the issue is in this case but it's best to avoid them on chips with so little (2kB) RAM.
I forgot to clarify i am using the Arduino mega (256kb ram), so I don't need to worry as much about ram issues.
Arduino mega (256kb ram)
The mega actually has 256kb of flash, not RAM. It has 8kb of RAM.
oops, misread the specs. Sorry. Well i would still like to be able to do this, regardless, even if i wont be able to do much. I have been considering getting a different microchip, would like some good recommendations preferably with wifi support and a decent amount of ram.
Alright, another issue i found... I cant write any pwm values, even with the 6 digital pins its limited to (limited by tinygo, the board itself has 11 or so dedicated pwm pins, none of which are used in tinygo D2-D12) Using a pin thats allowed by the library:
package main
import (
"machine"
"math"
"time"
)
const twoPi = float32(2 * math.Pi)
func timedOutput(pin machine.Pin) {
for {
time.Sleep(5 * time.Millisecond)
pin.High()
time.Sleep(5 * time.Millisecond)
pin.Low()
}
}
const (
sineB = 4.0 / math.Pi
sineC = -4.0 / (math.Pi * math.Pi)
Q = 0.775
sineP = 0.225
)
func abs(in float32) float32 {
if in < 0 {
return -in
}
return in
}
func sine(v float32) float32 {
x := float32(v)
y := sineB*x + sineC*x*(abs(x))
y = sineP*(y*(abs(y))-y) + y
return float32(y)
}
var currentTime = 0
func timeTracker() {
for {
currentTime++
time.Sleep(1)
}
}
func test() {
println("test2")
}
func main() {
machine.InitPWM()
pin := machine.PWM{Pin: machine.D2}
println(int(pin.Pin))
pin.Configure()
currentPhaseAngle := float32(0)
currentSample := float32(0)
phaseAngleIncr := 200 * twoPi / 44100
for {
currentSample++
if currentPhaseAngle < -math.Pi {
currentPhaseAngle += twoPi
} else if currentPhaseAngle > math.Pi {
currentPhaseAngle -= twoPi
}
out := 255/2*sine(currentPhaseAngle) + 255/2
intOut := uint16(out)
rem := out - float32(intOut)
if rem > .5 {
intOut++
}
pin.Set(intOut << 8)
println("Setting to", intOut)
currentPhaseAngle += phaseAngleIncr
time.Sleep(1 / 44100 * time.Second)
}
}
When using the same pin but with an arduino script this works fine, I would provide the source but I accidentally closed the window and didnt save, and dont want to re-create it.
The arduino mega pwm pins are: D2 - D13, D44 - D46 (38, 37, 53, 34, 59, 60, 61, 62, 12, 13, 14, 15, 85, 84, 83) https://www.arduino.cc/reference/en/language/functions/analog-io/analogwrite/
The short answer is that the ATmega2560 is a relatively recent addition and is not as well supported. The PWM is probably just not implemented.
Unfortunately I don't have an ATmega2560 so can't do it myself (if I had the time).
Oh ok. Also trying to figure out how to use the interrupts, how exactly would i do that w/ avr? I'm trying to make an interrupt for IRQ_TIMER0_OVF
(23) which should occur every microsecond and is what arduino uses for its timing.
I tried to do a few things, troublshooted from here
Check that you have enabled the interrupt source in the peripheral (step 2).
Not sure how i should do that, doesnt seem to be something that arduino deals with and its not linked to any pin afaik.
Check that you have enabled the interrupt with the intr.Enable() call (step 4).
No enable func w/ avr
Check that you are listening for the correct interrupt and not for an interrupt for a different peripheral, for example (step 1).
Actually found the interrupt code in avr src code before i found it in tinygo, but it matches.
interrupt.New(23, test)
func test(interrupt.Interrupt) {
println("test")
}
I'm trying to make an interrupt for
IRQ_TIMER0_OVF
(23) which should occur every microsecond and is what arduino uses for its timing.
You will need to check the ATmega328p datasheet. The Timer0 peripheral is not configured at startup, you'll need to do that manually (this is what the Arduino environment does for you, but TinyGo doesn't).
I dont have the time to create a pr, but i'll list the configuration needed to get the interrupt to work.
avr.TIMSK0.Set(avr.TIMSK0_TOIE0) // Enable timer0 overflow interrupt
avr.TCCR0B.Set(avr.TCCR0B_CS00) // Enable the timer without any prescaling
avr.TIFR0.Set(avr.TIFR0_TOV0) // Enable overflow interrupt flag
The info for prescaling is here Then, the overflow is dependant on the cpu's refresh rate.
Should be equal to machine.CPUFrequency() / (256 * 1)
ticks per second. (cpu frequency / timer overflow (256) * prescaling)
package main
import (
"device/avr"
"machine"
"runtime/interrupt"
)
var t = int32(0)
func trackTime(interrupt.Interrupt) {
t++
}
func main() {
avr.TIMSK0.Set(avr.TIMSK0_TOIE0)
avr.TCCR0B.Set(avr.TCCR0B_CS00)
avr.TIFR0.Set(avr.TIFR0_TOV0)
interrupt.New(avr.IRQ_TIMER0_OVF, trackTime)
// note that some accuracy could be lost with different cpus as i'm not using floats,
// for the mega 2560 though its a clean division.
cps := machine.CPUFrequency() / 256
for {
if t >= cps {
println("1 sec")
t = 0
}
}
}
Hi, I'm following this conversation as a newcomer in tinygoland. I try to understand this imported function avr.TIMSK0.Set(avr.TIMSK0_TOIE0). Could you please give me a link to the file where this function is defined on github? Grts F.P.
Thats in a generated file. You have to download the source, (recursively) and run make gen-device-avr
it should be at src/device/avr/atmega2560.go
once you generate it.
Thanks! I just have my arduino-nano blinking and found the files.
Alright. Note that the code i provided wont work for you, as the arduino nano uses sam iirc.
Looking at the digital inputs it doesnt look like anything is correct...
// getRegisterPortMask returns the register, port, and mask for the pin
func (p Pin) getRegisterPortMask() (*volatile.Register8, *volatile.Register8, uint8) {
switch {
case p >= PA0 && p <= PA7:
return avr.DDRA, avr.PORTA, 1 << uint8(p-portA)
case p >= PB0 && p <= PB7:
return avr.DDRB, avr.PORTB, 1 << uint8(p-portB)
case p >= PC0 && p <= PC7:
return avr.DDRC, avr.PORTC, 1 << uint8(p-portC)
case p >= PD0 && p <= PD7:
return avr.DDRD, avr.PORTD, 1 << uint8(p-portD)
case p >= PE0 && p <= PE6:
return avr.DDRE, avr.PORTE, 1 << uint8(p-portE)
case p >= PF0 && p <= PF7:
return avr.DDRF, avr.PORTF, 1 << uint8(p-portF)
case p >= PG0 && p <= PG5:
return avr.DDRG, avr.PORTG, 1 << uint8(p-portG)
case p >= PH0 && p <= PH6:
return avr.DDRH, avr.PORTH, 1 << uint8(p-portH)
case p >= PJ0 && p <= PJ1:
return avr.DDRJ, avr.PORTJ, 1 << uint8(p-portJ)
case p >= PK0 && p <= PK7:
return avr.DDRK, avr.PORTK, 1 << uint8(p-portK)
case p <= PL0 && p >= PL7:
return avr.DDRL, avr.PINL, 1 << uint8(p-portL)
default:
return avr.DDRB, avr.PORTA, 255
}
}
So there's a few things wrong here:
The pins that belong to the different ports arent in static ranges.
EG:
case p <= PL0 && p >= PL7:
Well if I'm using digital pin 43 *PL6) well...
PL0 == 80 and PL7 == 39
But PL6 == 86, so this wont catch it.
Let alone the fact that all of:
[
"PF0",
"PF1",
"PF2",
"PF3",
"PF4",
"PF5",
"PF6",
"PF7",
"PG0",
"PG1",
"PG2",
"PG5",
"PG6",
"PH0",
"PH1",
"PH3",
"PH4",
"PH5",
"PH6",
"PJ0",
"PJ1",
"PK0",
"PK1",
"PK2",
"PK3",
"PK4",
"PK5",
"PK6",
"PK7",
"PL0",
"PL7"
]
are in that range.
Now I made an exception for pin 86 (D43 and also PL6) yet it still didnt work. However, once I changed avr.PORTL to avr.PINL it worked, looks like PIN(X) is used instead of PORT(X) for getting the input of a pin.
@AllAwesome497 please try with the dev branch. There were a number of changes related to pins on AVR in the dev branch.
Havent had much time to work on this in a while, I'll see if it works now @aykevl
Edit: Ended up running out of time, will test next weekend if i get the chance.
Hello,
i have also some Problems with the MEGA2560 when i try to output float variables.
How to reproduce:
x :=5.5
y := 5.5
println(x + y)
After this, the serial terminal and the program hangs and the arduino is doing nothing anymore.
Ok, the issues with the pins seem to be fixed - now I'm getting everything to run correctly, I believe.
I think everything in the original issue has been resolved, so closing.
When trying to run gourotines:
Code: ```go package main import ( "time" ) var currentTime int func trackTime() { for { currentTime++ time.Sleep(1 * time.Microsecond) } } func main() { go trackTime() for { println(currentTime) } } ``` When trying to flash: ``` tinygo flash -target=arduino-mega2560 -port "/dev/ttyACM0" -ocd-output main.go > main.go:17:2: attempted to start a goroutine without a scheduler ```When trying to get the current time
Now i'd like to point out that I know arduino doesnt have a good time system, but they do have a `millis()` function that returns how long the arduino has been running in milliseconds. import ( "time" ) var currentTime int func main() { for { now := time.Now() println(now.String()) } } ``` When building: ```tinygo flash -target=arduino-mega2560 -port "/dev/ttyACM0" -ocd-output main.go /tmp/tinygo295588631/main.o: In function `LBB10_3': main.go:(.text.(reflect.Value).Complex+0x9a): undefined reference to `__extendsfdf2' /usr/lib/gcc/avr/5.4.0/../../../avr/bin/ld: Dwarf Error: found dwarf version '0', this reader only handles version 2, 3 and 4 information. main.go:(.text.(reflect.Value).Complex+0xba): undefined reference to `__extendsfdf2' /usr/lib/gcc/avr/5.4.0/../../../avr/bin/ld: Dwarf Error: found address size '9', this reader can not handle sizes greater than '8'. /tmp/tinygo295588631/main.o: In function `LBB12_3': main.go:(.text.(reflect.Value).Float+0x3c): undefined reference to `__extendsfdf2' /usr/lib/gcc/avr/5.4.0/../../../avr/bin/ld: Dwarf Error: found dwarf version '12', this reader only handles version 2, 3 and 4 information. /tmp/tinygo295588631/main.o: In function `LBB20_48': main.go:(.text.runtime._panic+0x2c4): undefined reference to `__extendsfdf2' /usr/lib/gcc/avr/5.4.0/../../../avr/bin/ld: Dwarf Error: found dwarf version '0', this reader only handles version 2, 3 and 4 information. /tmp/tinygo295588631/main.o: In function `LBB20_71': main.go:(.text.runtime._panic+0x3fa): undefined reference to `__extendsfdf2' /usr/lib/gcc/avr/5.4.0/../../../avr/bin/ld: Dwarf Error: found dwarf version '0', this reader only handles version 2, 3 and 4 information. /tmp/tinygo295588631/main.o:main.go:(.text.runtime._panic+0x406): more undefined references to `__extendsfdf2' follow /usr/lib/gcc/avr/5.4.0/../../../avr/bin/ld: Dwarf Error: found dwarf version '4354', this reader only handles version 2, 3 and 4 information. /tmp/tinygo295588631/main.o: In function `runtime.printfloat64': main.go:(.text.runtime.printfloat64+0x46): undefined reference to `__unorddf2' /usr/lib/gcc/avr/5.4.0/../../../avr/bin/ld: Dwarf Error: found dwarf version '13312', this reader only handles version 2, 3 and 4 information. main.go:(.text.runtime.printfloat64+0x64): undefined reference to `__ledf2' /usr/lib/gcc/avr/5.4.0/../../../avr/bin/ld: Dwarf Error: found dwarf version '256', this reader only handles version 2, 3 and 4 information. main.go:(.text.runtime.printfloat64+0x7a): undefined reference to `__adddf3' /usr/lib/gcc/avr/5.4.0/../../../avr/bin/ld: Dwarf Error: found dwarf version '65535', this reader only handles version 2, 3 and 4 information. main.go:(.text.runtime.printfloat64+0xb0): undefined reference to `__eqdf2' /usr/lib/gcc/avr/5.4.0/../../../avr/bin/ld: Dwarf Error: found dwarf version '17', this reader only handles version 2, 3 and 4 information. main.go:(.text.runtime.printfloat64+0xd6): undefined reference to `__unorddf2' /usr/lib/gcc/avr/5.4.0/../../../avr/bin/ld: Dwarf Error: found dwarf version '15619', this reader only handles version 2, 3 and 4 information. main.go:(.text.runtime.printfloat64+0x104): undefined reference to `__gedf2' /usr/lib/gcc/avr/5.4.0/../../../avr/bin/ld: Dwarf Error: found dwarf version '0', this reader only handles version 2, 3 and 4 information. main.go:(.text.runtime.printfloat64+0x126): undefined reference to `__eqdf2' /usr/lib/gcc/avr/5.4.0/../../../avr/bin/ld: Dwarf Error: found dwarf version '0', this reader only handles version 2, 3 and 4 information. main.go:(.text.runtime.printfloat64+0x14c): undefined reference to `__unorddf2' /usr/lib/gcc/avr/5.4.0/../../../avr/bin/ld: Dwarf Error: found dwarf version '0', this reader only handles version 2, 3 and 4 information. main.go:(.text.runtime.printfloat64+0x1d2): undefined reference to `__eqdf2' /usr/lib/gcc/avr/5.4.0/../../../avr/bin/ld: Dwarf Error: found dwarf version '1537', this reader only handles version 2, 3 and 4 information. main.go:(.text.runtime.printfloat64+0x1f4): undefined reference to `__unorddf2' /usr/lib/gcc/avr/5.4.0/../../../avr/bin/ld: Dwarf Error: found dwarf version '0', this reader only handles version 2, 3 and 4 information. main.go:(.text.runtime.printfloat64+0x282): undefined reference to `__gedf2' /usr/lib/gcc/avr/5.4.0/../../../avr/bin/ld: Dwarf Error: found dwarf version '0', this reader only handles version 2, 3 and 4 information. main.go:(.text.runtime.printfloat64+0x2a0): undefined reference to `__subdf3' /usr/lib/gcc/avr/5.4.0/../../../avr/bin/ld: Dwarf Error: found dwarf version '1792', this reader only handles version 2, 3 and 4 information. main.go:(.text.runtime.printfloat64+0x2ce): undefined reference to `__ltdf2' /usr/lib/gcc/avr/5.4.0/../../../avr/bin/ld: Dwarf Error: found dwarf version '0', this reader only handles version 2, 3 and 4 information. main.go:(.text.runtime.printfloat64+0x2ea): undefined reference to `__divdf3' /usr/lib/gcc/avr/5.4.0/../../../avr/bin/ld: Dwarf Error: found dwarf version '18946', this reader only handles version 2, 3 and 4 information. main.go:(.text.runtime.printfloat64+0x322): undefined reference to `__muldf3' /usr/lib/gcc/avr/5.4.0/../../../avr/bin/ld: Dwarf Error: found dwarf version '13312', this reader only handles version 2, 3 and 4 information. main.go:(.text.runtime.printfloat64+0x35c): undefined reference to `__gedf2' /usr/lib/gcc/avr/5.4.0/../../../avr/bin/ld: Dwarf Error: found dwarf version '256', this reader only handles version 2, 3 and 4 information. main.go:(.text.runtime.printfloat64+0x384): undefined reference to `__adddf3' /usr/lib/gcc/avr/5.4.0/../../../avr/bin/ld: Dwarf Error: found dwarf version '65535', this reader only handles version 2, 3 and 4 information. main.go:(.text.runtime.printfloat64+0x39e): undefined reference to `__ltdf2' /usr/lib/gcc/avr/5.4.0/../../../avr/bin/ld: Dwarf Error: found dwarf version '74', this reader only handles version 2, 3 and 4 information. main.go:(.text.runtime.printfloat64+0x3be): undefined reference to `__divdf3' /usr/lib/gcc/avr/5.4.0/../../../avr/bin/ld: Dwarf Error: found dwarf version '23042', this reader only handles version 2, 3 and 4 information. main.go:(.text.runtime.printfloat64+0x3f4): undefined reference to `__divdf3' /usr/lib/gcc/avr/5.4.0/../../../avr/bin/ld: Dwarf Error: found dwarf version '13312', this reader only handles version 2, 3 and 4 information. main.go:(.text.runtime.printfloat64+0x404): undefined reference to `__gedf2' /usr/lib/gcc/avr/5.4.0/../../../avr/bin/ld: Dwarf Error: found dwarf version '256', this reader only handles version 2, 3 and 4 information. main.go:(.text.runtime.printfloat64+0x458): undefined reference to `__fixdfsi' /usr/lib/gcc/avr/5.4.0/../../../avr/bin/ld: Dwarf Error: found dwarf version '65535', this reader only handles version 2, 3 and 4 information. main.go:(.text.runtime.printfloat64+0x470): undefined reference to `__floatsidf' /usr/lib/gcc/avr/5.4.0/../../../avr/bin/ld: Dwarf Error: found dwarf version '90', this reader only handles version 2, 3 and 4 information. main.go:(.text.runtime.printfloat64+0x484): undefined reference to `__subdf3' /usr/lib/gcc/avr/5.4.0/../../../avr/bin/ld: Dwarf Error: found dwarf version '26882', this reader only handles version 2, 3 and 4 information. main.go:(.text.runtime.printfloat64+0x49e): undefined reference to `__muldf3' /usr/lib/gcc/avr/5.4.0/../../../avr/bin/ld: Dwarf Error: found dwarf version '13312', this reader only handles version 2, 3 and 4 information. /tmp/tinygo295588631/main.o: In function `LBB40_15': main.go:(.text.runtime.reflectValueEqual+0x16c): undefined reference to `__eqdf2' /usr/lib/gcc/avr/5.4.0/../../../avr/bin/ld: Dwarf Error: found dwarf version '256', this reader only handles version 2, 3 and 4 information. main.go:(.text.runtime.reflectValueEqual+0x192): undefined reference to `__eqdf2' /usr/lib/gcc/avr/5.4.0/../../../avr/bin/ld: Dwarf Error: found dwarf version '65535', this reader only handles version 2, 3 and 4 information. /tmp/tinygo295588631/main.o: In function `LBB40_29': main.go:(.text.runtime.reflectValueEqual+0x31e): undefined reference to `__eqdf2' /usr/lib/gcc/avr/5.4.0/../../../avr/bin/ld: Dwarf Error: found dwarf version '105', this reader only handles version 2, 3 and 4 information. /tmp/tinygo295588631/main.o: In function `LBB40_31': main.go:(.text.runtime.reflectValueEqual+0x334): undefined reference to `__unorddf2' collect2: error: ld returned 1 exit status error: failed to link /tmp/tinygo295588631/main: exit status 1 ```There's also a lot of builtin arduino functions we cant use. Could you make a way for us to include Arduino.h via cgo?