Files
tinygo/src/machine/machine_atmega.go
T
Ayke van Laethem 6b8940421e avr: use standard pin numbering
This commit changes pin numbering for atmega328 based boards (Uno, Nano)
to use the standard format, where pin number is determined by the
pin/port. Previously, pin numbers were based on what the Uno uses, which
does not seem to have a clear pattern.

One difference is that counting starts at port B, as there is no port A.
So PB0 is 0, PB1 is 1… PC0 is 8.

This commit also moves PWM code to the atmega328 file, as it may not be
generic to all ATmega chips.
2020-05-12 08:16:34 +02:00

158 lines
4.2 KiB
Go

// +build avr,atmega
package machine
import (
"device/avr"
"runtime/interrupt"
)
// I2CConfig is used to store config info for I2C.
type I2CConfig struct {
Frequency uint32
}
// Configure is intended to setup the I2C interface.
func (i2c I2C) Configure(config I2CConfig) {
// Default I2C bus speed is 100 kHz.
if config.Frequency == 0 {
config.Frequency = TWI_FREQ_100KHZ
}
// Activate internal pullups for twi.
avr.PORTC.SetBits((avr.DIDR0_ADC4D | avr.DIDR0_ADC5D))
// Initialize twi prescaler and bit rate.
avr.TWSR.SetBits((avr.TWSR_TWPS0 | avr.TWSR_TWPS1))
// twi bit rate formula from atmega128 manual pg. 204:
// SCL Frequency = CPU Clock Frequency / (16 + (2 * TWBR))
// NOTE: TWBR should be 10 or higher for master mode.
// It is 72 for a 16mhz board with 100kHz TWI
avr.TWBR.Set(uint8(((CPUFrequency() / config.Frequency) - 16) / 2))
// Enable twi module.
avr.TWCR.Set(avr.TWCR_TWEN)
}
// Tx does a single I2C transaction at the specified address.
// It clocks out the given address, writes the bytes in w, reads back len(r)
// bytes and stores them in r, and generates a stop condition on the bus.
func (i2c I2C) Tx(addr uint16, w, r []byte) error {
if len(w) != 0 {
i2c.start(uint8(addr), true) // start transmission for writing
for _, b := range w {
i2c.writeByte(b)
}
}
if len(r) != 0 {
i2c.start(uint8(addr), false) // re-start transmission for reading
for i := range r { // read each char
r[i] = i2c.readByte()
}
}
if len(w) != 0 || len(r) != 0 {
// Stop the transmission after it has been started.
i2c.stop()
}
return nil
}
// start starts an I2C communication session.
func (i2c I2C) start(address uint8, write bool) {
// Clear TWI interrupt flag, put start condition on SDA, and enable TWI.
avr.TWCR.Set((avr.TWCR_TWINT | avr.TWCR_TWSTA | avr.TWCR_TWEN))
// Wait till start condition is transmitted.
for !avr.TWCR.HasBits(avr.TWCR_TWINT) {
}
// Write 7-bit shifted peripheral address.
address <<= 1
if !write {
address |= 1 // set read flag
}
i2c.writeByte(address)
}
// stop ends an I2C communication session.
func (i2c I2C) stop() {
// Send stop condition.
avr.TWCR.Set(avr.TWCR_TWEN | avr.TWCR_TWINT | avr.TWCR_TWSTO)
// Wait for stop condition to be executed on bus.
for !avr.TWCR.HasBits(avr.TWCR_TWSTO) {
}
}
// writeByte writes a single byte to the I2C bus.
func (i2c I2C) writeByte(data byte) {
// Write data to register.
avr.TWDR.Set(data)
// Clear TWI interrupt flag and enable TWI.
avr.TWCR.Set(avr.TWCR_TWEN | avr.TWCR_TWINT)
// Wait till data is transmitted.
for !avr.TWCR.HasBits(avr.TWCR_TWINT) {
}
}
// readByte reads a single byte from the I2C bus.
func (i2c I2C) readByte() byte {
// Clear TWI interrupt flag and enable TWI.
avr.TWCR.Set(avr.TWCR_TWEN | avr.TWCR_TWINT | avr.TWCR_TWEA)
// Wait till read request is transmitted.
for !avr.TWCR.HasBits(avr.TWCR_TWINT) {
}
return byte(avr.TWDR.Get())
}
// UART on the AVR.
type UART struct {
Buffer *RingBuffer
}
// Configure the UART on the AVR. Defaults to 9600 baud on Arduino.
func (uart UART) Configure(config UARTConfig) {
if config.BaudRate == 0 {
config.BaudRate = 9600
}
// Register the UART interrupt.
interrupt.New(irq_USART0_RX, func(intr interrupt.Interrupt) {
// Read register to clear it.
data := avr.UDR0.Get()
// Ensure no error.
if !avr.UCSR0A.HasBits(avr.UCSR0A_FE0 | avr.UCSR0A_DOR0 | avr.UCSR0A_UPE0) {
// Put data from UDR register into buffer.
UART0.Receive(byte(data))
}
})
// Set baud rate based on prescale formula from
// https://www.microchip.com/webdoc/AVRLibcReferenceManual/FAQ_1faq_wrong_baud_rate.html
// ((F_CPU + UART_BAUD_RATE * 8L) / (UART_BAUD_RATE * 16L) - 1)
ps := ((CPUFrequency()+config.BaudRate*8)/(config.BaudRate*16) - 1)
avr.UBRR0H.Set(uint8(ps >> 8))
avr.UBRR0L.Set(uint8(ps & 0xff))
// enable RX, TX and RX interrupt
avr.UCSR0B.Set(avr.UCSR0B_RXEN0 | avr.UCSR0B_TXEN0 | avr.UCSR0B_RXCIE0)
// 8-bits data
avr.UCSR0C.Set(avr.UCSR0C_UCSZ01 | avr.UCSR0C_UCSZ00)
}
// WriteByte writes a byte of data to the UART.
func (uart UART) WriteByte(c byte) error {
// Wait until UART buffer is not busy.
for !avr.UCSR0A.HasBits(avr.UCSR0A_UDRE0) {
}
avr.UDR0.Set(c) // send char
return nil
}