1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
|
//go:build avr && atmega
package machine
import (
"device/avr"
"runtime/interrupt"
"runtime/volatile"
"unsafe"
)
// I2C on AVR.
type I2C struct {
srReg *volatile.Register8
brReg *volatile.Register8
crReg *volatile.Register8
drReg *volatile.Register8
srPS0 byte
srPS1 byte
crEN byte
crINT byte
crSTO byte
crEA byte
crSTA byte
}
// 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) error {
// Default I2C bus speed is 100 kHz.
if config.Frequency == 0 {
config.Frequency = 100 * KHz
}
// Activate internal pullups for twi.
avr.PORTC.SetBits((avr.DIDR0_ADC4D | avr.DIDR0_ADC5D))
return i2c.SetBaudRate(config.Frequency)
}
// SetBaudRate sets the communication speed for I2C.
func (i2c *I2C) SetBaudRate(br uint32) error {
// Initialize twi prescaler and bit rate.
i2c.srReg.SetBits((i2c.srPS0 | i2c.srPS1))
// 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 controller mode.
// It is 72 for a 16mhz board with 100kHz TWI
i2c.brReg.Set(uint8(((CPUFrequency() / br) - 16) / 2))
// Enable twi module.
i2c.crReg.Set(i2c.crEN)
return nil
}
// 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.
i2c.crReg.Set((i2c.crINT | i2c.crSTA | i2c.crEN))
// Wait till start condition is transmitted.
for !i2c.crReg.HasBits(i2c.crINT) {
}
// 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.
i2c.crReg.Set(i2c.crEN | i2c.crINT | i2c.crSTO)
// Wait for stop condition to be executed on bus.
for !i2c.crReg.HasBits(i2c.crSTO) {
}
}
// writeByte writes a single byte to the I2C bus.
func (i2c *I2C) writeByte(data byte) error {
// Write data to register.
i2c.drReg.Set(data)
// Clear TWI interrupt flag and enable TWI.
i2c.crReg.Set(i2c.crEN | i2c.crINT)
// Wait till data is transmitted.
for !i2c.crReg.HasBits(i2c.crINT) {
}
return nil
}
// readByte reads a single byte from the I2C bus.
func (i2c *I2C) readByte() byte {
// Clear TWI interrupt flag and enable TWI.
i2c.crReg.Set(i2c.crEN | i2c.crINT | i2c.crEA)
// Wait till read request is transmitted.
for !i2c.crReg.HasBits(i2c.crINT) {
}
return byte(i2c.drReg.Get())
}
// Always use UART0 as the serial output.
var DefaultUART = UART0
// UART
var (
// UART0 is the hardware serial port on the AVR.
UART0 = &_UART0
_UART0 = UART{
Buffer: NewRingBuffer(),
dataReg: avr.UDR0,
baudRegH: avr.UBRR0H,
baudRegL: avr.UBRR0L,
statusRegA: avr.UCSR0A,
statusRegB: avr.UCSR0B,
statusRegC: avr.UCSR0C,
}
)
func init() {
// Register the UART interrupt.
interrupt.New(irq_USART0_RX, _UART0.handleInterrupt)
}
// UART on the AVR.
type UART struct {
Buffer *RingBuffer
dataReg *volatile.Register8
baudRegH *volatile.Register8
baudRegL *volatile.Register8
statusRegA *volatile.Register8
statusRegB *volatile.Register8
statusRegC *volatile.Register8
}
// 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
}
// Prescale formula for u2x mode from AVR MiniCore source code.
// Same as formula from specification but taking into account rounding error.
ps := (CPUFrequency()/4/config.BaudRate - 1) / 2
uart.statusRegA.SetBits(avr.UCSR0A_U2X0)
// Hardcoded exception for 57600 for compatibility with older bootloaders.
// Also, prescale cannot be > 4095, so switch back to non-u2x mode if the baud rate is too low.
if (CPUFrequency() == 16000000 && config.BaudRate == 57600) || ps > 0xfff {
ps = (CPUFrequency()/8/config.BaudRate - 1) / 2
uart.statusRegA.ClearBits(avr.UCSR0A_U2X0)
}
uart.baudRegH.Set(uint8(ps >> 8))
uart.baudRegL.Set(uint8(ps & 0xff))
// enable RX, TX and RX interrupt
uart.statusRegB.Set(avr.UCSR0B_RXEN0 | avr.UCSR0B_TXEN0 | avr.UCSR0B_RXCIE0)
// 8-bits data
uart.statusRegC.Set(avr.UCSR0C_UCSZ01 | avr.UCSR0C_UCSZ00)
}
func (uart *UART) handleInterrupt(intr interrupt.Interrupt) {
// Read register to clear it.
data := uart.dataReg.Get()
// Ensure no error.
if !uart.statusRegA.HasBits(avr.UCSR0A_FE0 | avr.UCSR0A_DOR0 | avr.UCSR0A_UPE0) {
// Put data from UDR register into buffer.
uart.Receive(byte(data))
}
}
// WriteByte writes a byte of data to the UART.
func (uart *UART) writeByte(c byte) error {
// Wait until UART buffer is not busy.
for !uart.statusRegA.HasBits(avr.UCSR0A_UDRE0) {
}
uart.dataReg.Set(c) // send char
return nil
}
func (uart *UART) flush() {}
// SPIConfig is used to store config info for SPI.
type SPIConfig struct {
Frequency uint32
LSBFirst bool
Mode uint8
}
// SPI is for the Serial Peripheral Interface
// Data is taken from http://ww1.microchip.com/downloads/en/DeviceDoc/ATmega48A-PA-88A-PA-168A-PA-328-P-DS-DS40002061A.pdf page 169 and following
type SPI struct {
// The registers for the SPIx port set by the chip
spcr *volatile.Register8
spdr *volatile.Register8
spsr *volatile.Register8
spcrR0 byte
spcrR1 byte
spcrCPHA byte
spcrCPOL byte
spcrDORD byte
spcrSPE byte
spcrMSTR byte
spsrI2X byte
spsrSPIF byte
// The io pins for the SPIx port set by the chip
sck Pin
sdi Pin
sdo Pin
cs Pin
}
// Configure is intended to setup the SPI interface.
func (s SPI) Configure(config SPIConfig) error {
// This is only here to help catch a bug with the configuration
// where a machine missed a value.
if s.spcr == (*volatile.Register8)(unsafe.Pointer(uintptr(0))) ||
s.spsr == (*volatile.Register8)(unsafe.Pointer(uintptr(0))) ||
s.spdr == (*volatile.Register8)(unsafe.Pointer(uintptr(0))) ||
s.sck == 0 || s.sdi == 0 || s.sdo == 0 || s.cs == 0 {
return errSPIInvalidMachineConfig
}
// Make the defaults meaningful
if config.Frequency == 0 {
config.Frequency = 4000000
}
// Default all port configuration bits to 0 for simplicity
s.spcr.Set(0)
s.spsr.Set(0)
// Setup pins output configuration
s.sck.Configure(PinConfig{Mode: PinOutput})
s.sdi.Configure(PinConfig{Mode: PinInput})
s.sdo.Configure(PinConfig{Mode: PinOutput})
// Prevent CS glitches if the pin is enabled Low (0, default)
s.cs.High()
// If the CS pin is not configured as output the SPI port operates in
// slave mode.
s.cs.Configure(PinConfig{Mode: PinOutput})
frequencyDivider := CPUFrequency() / config.Frequency
switch {
case frequencyDivider >= 128:
s.spcr.SetBits(s.spcrR0 | s.spcrR1)
case frequencyDivider >= 64:
s.spcr.SetBits(s.spcrR1)
case frequencyDivider >= 32:
s.spcr.SetBits(s.spcrR1)
s.spsr.SetBits(s.spsrI2X)
case frequencyDivider >= 16:
s.spcr.SetBits(s.spcrR0)
case frequencyDivider >= 8:
s.spcr.SetBits(s.spcrR0)
s.spsr.SetBits(s.spsrI2X)
case frequencyDivider >= 4:
// The clock is already set to all 0's.
default: // defaults to fastest which is /2
s.spsr.SetBits(s.spsrI2X)
}
switch config.Mode {
case Mode1:
s.spcr.SetBits(s.spcrCPHA)
case Mode2:
s.spcr.SetBits(s.spcrCPHA)
case Mode3:
s.spcr.SetBits(s.spcrCPHA | s.spcrCPOL)
default: // default is mode 0
}
if config.LSBFirst {
s.spcr.SetBits(s.spcrDORD)
}
// enable SPI, set controller, set clock rate
s.spcr.SetBits(s.spcrSPE | s.spcrMSTR)
return nil
}
// Transfer writes the byte into the register and returns the read content
func (s SPI) Transfer(b byte) (byte, error) {
s.spdr.Set(uint8(b))
for !s.spsr.HasBits(s.spsrSPIF) {
}
return byte(s.spdr.Get()), nil
}
|