diff --git a/emb/machine/_usb/adc/doc.go b/emb/machine/_usb/adc/doc.go deleted file mode 100644 index beed33c..0000000 --- a/emb/machine/_usb/adc/doc.go +++ /dev/null @@ -1,2 +0,0 @@ -// package adc is for USB Audio Device Class devices. -package adc diff --git a/emb/machine/_usb/adc/midi/buffer.go b/emb/machine/_usb/adc/midi/buffer.go deleted file mode 100644 index 39cab2c..0000000 --- a/emb/machine/_usb/adc/midi/buffer.go +++ /dev/null @@ -1,52 +0,0 @@ -package midi - -import ( - "runtime/volatile" -) - -const bufferSize = 128 - -// RingBuffer is ring buffer implementation inspired by post at -// https://www.embeddedrelated.com/showthread/comp.arch.embedded/77084-1.php -type RingBuffer struct { - rxbuffer [bufferSize][4]byte - head volatile.Register8 - tail volatile.Register8 -} - -// NewRingBuffer returns a new ring buffer. -func NewRingBuffer() *RingBuffer { - return &RingBuffer{} -} - -// Used returns how many bytes in buffer have been used. -func (rb *RingBuffer) Used() uint8 { - return uint8(rb.head.Get() - rb.tail.Get()) -} - -// Put stores a byte in the buffer. If the buffer is already -// full, the method will return false. -func (rb *RingBuffer) Put(val []byte) bool { - if rb.Used() != bufferSize { - rb.head.Set(rb.head.Get() + 1) - copy(rb.rxbuffer[rb.head.Get()%bufferSize][:], val) - return true - } - return false -} - -// Get returns a byte from the buffer. If the buffer is empty, -// the method will return a false as the second value. -func (rb *RingBuffer) Get() ([]byte, bool) { - if rb.Used() != 0 { - rb.tail.Set(rb.tail.Get() + 1) - return rb.rxbuffer[rb.tail.Get()%bufferSize][:], true - } - return nil, false -} - -// Clear resets the head and tail pointer to zero. -func (rb *RingBuffer) Clear() { - rb.head.Set(0) - rb.tail.Set(0) -} diff --git a/emb/machine/_usb/adc/midi/messages.go b/emb/machine/_usb/adc/midi/messages.go deleted file mode 100644 index c123acb..0000000 --- a/emb/machine/_usb/adc/midi/messages.go +++ /dev/null @@ -1,233 +0,0 @@ -package midi - -import ( - "errors" -) - -// From USB-MIDI section 4.1 "Code Index Number (CIN) Classifications" -const ( - CINSystemCommon2 = 0x2 - CINSystemCommon3 = 0x3 - CINSysExStart = 0x4 - CINSysExEnd1 = 0x5 - CINSysExEnd2 = 0x6 - CINSysExEnd3 = 0x7 - CINNoteOff = 0x8 - CINNoteOn = 0x9 - CINPoly = 0xA - CINControlChange = 0xB - CINProgramChange = 0xC - CINChannelPressure = 0xD - CINPitchBendChange = 0xE - CINSingleByte = 0xF -) - -// Standard MIDI channel messages -const ( - MsgNoteOff = 0x80 - MsgNoteOn = 0x90 - MsgPolyAftertouch = 0xA0 - MsgControlChange = 0xB0 - MsgProgramChange = 0xC0 - MsgChannelAftertouch = 0xD0 - MsgPitchBend = 0xE0 - MsgSysExStart = 0xF0 - MsgSysExEnd = 0xF7 -) - -// Standard MIDI control change messages -const ( - CCModulationWheel = 0x01 - CCBreathController = 0x02 - CCFootPedal = 0x04 - CCPortamentoTime = 0x05 - CCDataEntry = 0x06 - CCVolume = 0x07 - CCBalance = 0x08 - CCPan = 0x0A - CCExpression = 0x0B - CCEffectControl1 = 0x0C - CCEffectControl2 = 0x0D - CCGeneralPurpose1 = 0x10 - CCGeneralPurpose2 = 0x11 - CCGeneralPurpose3 = 0x12 - CCGeneralPurpose4 = 0x13 - CCBankSelect = 0x20 - CCModulationDepthRange = 0x21 - CCBreathControllerDepth = 0x22 - CCFootPedalDepth = 0x24 - CCEffectsLevel = 0x5B - CCTremeloLevel = 0x5C - CCChorusLevel = 0x5D - CCCelesteLevel = 0x5E - CCPhaserLevel = 0x5F - CCDataIncrement = 0x60 - CCDataDecrement = 0x61 - CCNRPNLSB = 0x62 - CCNRPNMSB = 0x63 - CCRPNLSB = 0x64 - CCRPNMSB = 0x65 - CCAllSoundOff = 0x78 - CCResetAllControllers = 0x79 - CCAllNotesOff = 0x7B - CCChannelVolume = 0x7F -) - -var ( - errInvalidMIDICable = errors.New("invalid MIDI cable") - errInvalidMIDIChannel = errors.New("invalid MIDI channel") - errInvalidMIDIVelocity = errors.New("invalid MIDI velocity") - errInvalidMIDIControl = errors.New("invalid MIDI control number") - errInvalidMIDIControlValue = errors.New("invalid MIDI control value") - errInvalidMIDIPatch = errors.New("invalid MIDI patch number") - errInvalidMIDIPitchBend = errors.New("invalid MIDI pitch bend value") - errInvalidMIDISysExData = errors.New("invalid MIDI SysEx data") -) - -// NoteOn sends a channel note on message. -// The cable parameter is the cable number 0-15. -// The channel parameter is the MIDI channel number 1-16. -func (m *midi) NoteOn(cable, channel uint8, note Note, velocity uint8) error { - switch { - case cable > 15: - return errInvalidMIDICable - case channel == 0 || channel > 16: - return errInvalidMIDIChannel - case velocity > 127: - return errInvalidMIDIVelocity - } - - m.msg[0], m.msg[1], m.msg[2], m.msg[3] = ((cable&0xf)<<4)|CINNoteOn, MsgNoteOn|((channel-1)&0xf), byte(note)&0x7f, velocity&0x7f - _, err := m.Write(m.msg[:]) - return err -} - -// NoteOff sends a channel note off message. -// The cable parameter is the cable number 0-15. -// The channel parameter is the MIDI channel number 1-16. -func (m *midi) NoteOff(cable, channel uint8, note Note, velocity uint8) error { - switch { - case cable > 15: - return errInvalidMIDICable - case channel == 0 || channel > 16: - return errInvalidMIDIChannel - case velocity > 127: - return errInvalidMIDIVelocity - } - - m.msg[0], m.msg[1], m.msg[2], m.msg[3] = ((cable&0xf)<<4)|CINNoteOff, MsgNoteOff|((channel-1)&0xf), byte(note)&0x7f, velocity&0x7f - _, err := m.Write(m.msg[:]) - return err -} - -// ControlChange sends a channel continuous controller message. -// The cable parameter is the cable number 0-15. -// The channel parameter is the MIDI channel number 1-16. -// The control parameter is the controller number 0-127. -// The value parameter is the controller value 0-127. -func (m *midi) ControlChange(cable, channel, control, value uint8) error { - switch { - case cable > 15: - return errInvalidMIDICable - case channel == 0 || channel > 16: - return errInvalidMIDIChannel - case control > 127: - return errInvalidMIDIControl - case value > 127: - return errInvalidMIDIControlValue - } - - m.msg[0], m.msg[1], m.msg[2], m.msg[3] = ((cable&0xf)<<4)|CINControlChange, MsgControlChange|((channel-1)&0xf), control&0x7f, value&0x7f - _, err := m.Write(m.msg[:]) - return err -} - -// ProgramChange sends a channel program change message. -// The cable parameter is the cable number 0-15. -// The channel parameter is the MIDI channel number 1-16. -// The patch parameter is the program number 0-127. -func (m *midi) ProgramChange(cable, channel uint8, patch uint8) error { - switch { - case cable > 15: - return errInvalidMIDICable - case channel == 0 || channel > 16: - return errInvalidMIDIChannel - case patch > 127: - return errInvalidMIDIPatch - } - - m.msg[0], m.msg[1], m.msg[2] = ((cable&0xf)<<4)|CINProgramChange, MsgProgramChange|((channel-1)&0xf), patch&0x7f - _, err := m.Write(m.msg[:3]) - return err -} - -// PitchBend sends a channel pitch bend message. -// The cable parameter is the cable number 0-15. -// The channel parameter is the MIDI channel number 1-16. -// The bend parameter is the 14-bit pitch bend value (maximum 0x3FFF). -// Setting bend above 0x2000 (up to 0x3FFF) will increase the pitch. -// Setting bend below 0x2000 (down to 0x0000) will decrease the pitch. -func (m *midi) PitchBend(cable, channel uint8, bend uint16) error { - switch { - case cable > 15: - return errInvalidMIDICable - case channel == 0 || channel > 16: - return errInvalidMIDIChannel - case bend > 0x3FFF: - return errInvalidMIDIPitchBend - } - - m.msg[0], m.msg[1], m.msg[2], m.msg[3] = ((cable&0xf)<<4)|CINPitchBendChange, MsgPitchBend|((channel-1)&0xf), byte(bend&0x7f), byte(bend>>7)&0x7f - _, err := m.Write(m.msg[:]) - return err -} - -// SysEx sends a System Exclusive message. -// The cable parameter is the cable number 0-15. -// The data parameter is a slice with the data to send. -// It needs to start with the manufacturer ID, which is either -// 1 or 3 bytes in length. -// The data slice should not include the SysEx start (0xF0) or -// end (0xF7) bytes, only the data in between. -func (m *midi) SysEx(cable uint8, data []byte) error { - switch { - case cable > 15: - return errInvalidMIDICable - case len(data) < 3: - return errInvalidMIDISysExData - } - - // write start - m.msg[0], m.msg[1] = ((cable&0xf)<<4)|CINSysExStart, MsgSysExStart - m.msg[2], m.msg[3] = data[0], data[1] - if _, err := m.Write(m.msg[:]); err != nil { - return err - } - - // write middle - i := 2 - for ; i < len(data)-2; i += 3 { - m.msg[0], m.msg[1] = ((cable&0xf)<<4)|CINSysExStart, data[i] - m.msg[2], m.msg[3] = data[i+1], data[i+2] - if _, err := m.Write(m.msg[:]); err != nil { - return err - } - } - // write end - switch len(data) - i { - case 2: - m.msg[0], m.msg[1] = ((cable&0xf)<<4)|CINSysExEnd3, data[i] - m.msg[2], m.msg[3] = data[i+1], MsgSysExEnd - case 1: - m.msg[0], m.msg[1] = ((cable&0xf)<<4)|CINSysExEnd2, data[i] - m.msg[2], m.msg[3] = MsgSysExEnd, 0 - case 0: - m.msg[0], m.msg[1] = ((cable&0xf)<<4)|CINSysExEnd1, MsgSysExEnd - m.msg[2], m.msg[3] = 0, 0 - } - if _, err := m.Write(m.msg[:]); err != nil { - return err - } - - return nil -} diff --git a/emb/machine/_usb/adc/midi/midi.go b/emb/machine/_usb/adc/midi/midi.go deleted file mode 100644 index 8ead2e9..0000000 --- a/emb/machine/_usb/adc/midi/midi.go +++ /dev/null @@ -1,127 +0,0 @@ -package midi - -import ( - "machine" - "machine/usb" - "machine/usb/descriptor" -) - -const ( - midiEndpointOut = usb.MIDI_ENDPOINT_OUT // from PC - midiEndpointIn = usb.MIDI_ENDPOINT_IN // to PC -) - -var Midi *midi - -type midi struct { - msg [4]byte - buf *RingBuffer - rxHandler func([]byte) - txHandler func() - waitTxc bool -} - -func init() { - if Midi == nil { - Midi = newMidi() - } -} - -// New returns the USB MIDI port. -// Deprecated, better to just use Port() -func New() *midi { - return Port() -} - -// Port returns the USB midi port. -func Port() *midi { - return Midi -} - -func newMidi() *midi { - m := &midi{ - buf: NewRingBuffer(), - } - machine.ConfigureUSBEndpoint(descriptor.CDCMIDI, - []usb.EndpointConfig{ - { - Index: usb.MIDI_ENDPOINT_OUT, - IsIn: false, - Type: usb.ENDPOINT_TYPE_BULK, - RxHandler: m.RxHandler, - }, - { - Index: usb.MIDI_ENDPOINT_IN, - IsIn: true, - Type: usb.ENDPOINT_TYPE_BULK, - TxHandler: m.TxHandler, - }, - }, - []usb.SetupConfig{}, - ) - return m -} - -// SetHandler is now deprecated, please use SetRxHandler(). -func (m *midi) SetHandler(rxHandler func([]byte)) { - m.SetRxHandler(rxHandler) -} - -// SetRxHandler sets the handler function for incoming MIDI messages. -func (m *midi) SetRxHandler(rxHandler func([]byte)) { - m.rxHandler = rxHandler -} - -// SetTxHandler sets the handler function for outgoing MIDI messages. -func (m *midi) SetTxHandler(txHandler func()) { - m.txHandler = txHandler -} - -func (m *midi) Write(b []byte) (n int, err error) { - s, e := 0, 0 - for s = 0; s < len(b); s += 4 { - e = s + 4 - if e > len(b) { - e = len(b) - } - - m.tx(b[s:e]) - } - return e, nil -} - -// sendUSBPacket sends a MIDIPacket. -func (m *midi) sendUSBPacket(b []byte) { - machine.SendUSBInPacket(midiEndpointIn, b) -} - -// from BulkIn -func (m *midi) TxHandler() { - if m.txHandler != nil { - m.txHandler() - } - - m.waitTxc = false - if b, ok := m.buf.Get(); ok { - m.waitTxc = true - m.sendUSBPacket(b) - } -} - -func (m *midi) tx(b []byte) { - if machine.USBDev.InitEndpointComplete { - if m.waitTxc { - m.buf.Put(b) - } else { - m.waitTxc = true - m.sendUSBPacket(b) - } - } -} - -// from BulkOut -func (m *midi) RxHandler(b []byte) { - if m.rxHandler != nil { - m.rxHandler(b) - } -} diff --git a/emb/machine/_usb/adc/midi/notes.go b/emb/machine/_usb/adc/midi/notes.go deleted file mode 100644 index 05fa681..0000000 --- a/emb/machine/_usb/adc/midi/notes.go +++ /dev/null @@ -1,108 +0,0 @@ -package midi - -// Note represents a MIDI note number. For example, Note(69) is A4 or 440Hz. -type Note uint8 - -// Define all the notes in a format similar to the Tone library in the Arduino -// IDE. -const ( - A0 Note = iota + 21 // 27.5Hz - AS0 - B0 - C1 - CS1 - D1 - DS1 - E1 - F1 - FS1 - G1 - GS1 - A1 // 55Hz - AS1 - B1 - C2 - CS2 - D2 - DS2 - E2 - F2 - FS2 - G2 - GS2 - A2 // 110Hz - AS2 - B2 - C3 - CS3 - D3 - DS3 - E3 - F3 - FS3 - G3 - GS3 - A3 // 220Hz - AS3 - B3 - C4 - CS4 - D4 - DS4 - E4 - F4 - FS4 - G4 - GS4 - A4 // 440Hz - AS4 - B4 - C5 - CS5 - D5 - DS5 - E5 - F5 - FS5 - G5 - GS5 - A5 // 880Hz - AS5 - B5 - C6 - CS6 - D6 - DS6 - E6 - F6 - FS6 - G6 - GS6 - A6 // 1760Hz - AS6 - B6 - C7 - CS7 - D7 - DS7 - E7 - F7 - FS7 - G7 - GS7 - A7 // 3520Hz - AS7 - B7 - C8 - CS8 - D8 - DS8 - E8 - F8 - FS8 - G8 - GS8 - A8 // 7040Hz - AS8 - B8 -) diff --git a/emb/machine/_usb/cdc/buffer.go b/emb/machine/_usb/cdc/buffer.go deleted file mode 100644 index ad5eb36..0000000 --- a/emb/machine/_usb/cdc/buffer.go +++ /dev/null @@ -1,119 +0,0 @@ -package cdc - -import ( - "runtime/volatile" -) - -const rxRingBufferSize = 128 - -// rxRingBuffer is ring buffer implementation inspired by post at -// https://www.embeddedrelated.com/showthread/comp.arch.embedded/77084-1.php -type rxRingBuffer struct { - buffer [rxRingBufferSize]volatile.Register8 - head volatile.Register8 - tail volatile.Register8 -} - -// NewRxRingBuffer returns a new ring buffer. -func NewRxRingBuffer() *rxRingBuffer { - return &rxRingBuffer{} -} - -// Used returns how many bytes in buffer have been used. -func (rb *rxRingBuffer) Used() uint8 { - return uint8(rb.head.Get() - rb.tail.Get()) -} - -// Put stores a byte in the buffer. If the buffer is already -// full, the method will return false. -func (rb *rxRingBuffer) Put(val byte) bool { - if rb.Used() != rxRingBufferSize { - rb.head.Set(rb.head.Get() + 1) - rb.buffer[rb.head.Get()%rxRingBufferSize].Set(val) - return true - } - return false -} - -// Get returns a byte from the buffer. If the buffer is empty, -// the method will return a false as the second value. -func (rb *rxRingBuffer) Get() (byte, bool) { - if rb.Used() != 0 { - rb.tail.Set(rb.tail.Get() + 1) - return rb.buffer[rb.tail.Get()%rxRingBufferSize].Get(), true - } - return 0, false -} - -// Clear resets the head and tail pointer to zero. -func (rb *rxRingBuffer) Clear() { - rb.head.Set(0) - rb.tail.Set(0) -} - -const txRingBufferSize = 8 - -// txRingBuffer is ring buffer implementation inspired by post at -// https://www.embeddedrelated.com/showthread/comp.arch.embedded/77084-1.php -type txRingBuffer struct { - buffer [txRingBufferSize]struct { - buf [64]byte - size int - } - head volatile.Register8 - tail volatile.Register8 -} - -// NewTxRingBuffer returns a new ring buffer. -func NewTxRingBuffer() *txRingBuffer { - return &txRingBuffer{} -} - -// Used returns how many bytes in buffer have been used. -func (rb *txRingBuffer) Used() uint8 { - return uint8(rb.head.Get() - rb.tail.Get()) -} - -// Put stores a byte in the buffer. If the buffer is already -// full, the method will return false. -func (rb *txRingBuffer) Put(val []byte) bool { - if rb.Used() == txRingBufferSize { - return false - } - - if rb.Used() == 0 { - rb.head.Set(rb.head.Get() + 1) - rb.buffer[rb.head.Get()%txRingBufferSize].size = 0 - } - buf := &rb.buffer[rb.head.Get()%txRingBufferSize] - - for i := 0; i < len(val); i++ { - if buf.size == 64 { - // next - // TODO: Make sure that data is not corrupted even when the buffer is full - rb.head.Set(rb.head.Get() + 1) - buf = &rb.buffer[rb.head.Get()%txRingBufferSize] - rb.buffer[rb.head.Get()%txRingBufferSize].size = 0 - } - buf.buf[buf.size] = val[i] - buf.size++ - } - return true -} - -// Get returns a byte from the buffer. If the buffer is empty, -// the method will return a false as the second value. -func (rb *txRingBuffer) Get() ([]byte, bool) { - if rb.Used() != 0 { - rb.tail.Set(rb.tail.Get() + 1) - size := rb.buffer[rb.tail.Get()%txRingBufferSize].size - return rb.buffer[rb.tail.Get()%txRingBufferSize].buf[:size], true - } - return nil, false -} - -// Clear resets the head and tail pointer to zero. -func (rb *txRingBuffer) Clear() { - rb.head.Set(0) - rb.tail.Set(0) -} diff --git a/emb/machine/_usb/cdc/cdc.go b/emb/machine/_usb/cdc/cdc.go deleted file mode 100644 index f180535..0000000 --- a/emb/machine/_usb/cdc/cdc.go +++ /dev/null @@ -1,61 +0,0 @@ -package cdc - -const ( - cdcEndpointACM = 1 - cdcEndpointOut = 2 - cdcEndpointIn = 3 -) - -// New returns USBCDC struct. -func New() *USBCDC { - if USB == nil { - USB = &USBCDC{ - rxBuffer: NewRxRingBuffer(), - txBuffer: NewTxRingBuffer(), - } - } - return USB -} - -const ( - // bmRequestType - usb_REQUEST_HOSTTODEVICE = 0x00 - usb_REQUEST_DEVICETOHOST = 0x80 - usb_REQUEST_DIRECTION = 0x80 - - usb_REQUEST_STANDARD = 0x00 - usb_REQUEST_CLASS = 0x20 - usb_REQUEST_VENDOR = 0x40 - usb_REQUEST_TYPE = 0x60 - - usb_REQUEST_DEVICE = 0x00 - usb_REQUEST_INTERFACE = 0x01 - usb_REQUEST_ENDPOINT = 0x02 - usb_REQUEST_OTHER = 0x03 - usb_REQUEST_RECIPIENT = 0x1F - - usb_REQUEST_DEVICETOHOST_CLASS_INTERFACE = (usb_REQUEST_DEVICETOHOST | usb_REQUEST_CLASS | usb_REQUEST_INTERFACE) - usb_REQUEST_HOSTTODEVICE_CLASS_INTERFACE = (usb_REQUEST_HOSTTODEVICE | usb_REQUEST_CLASS | usb_REQUEST_INTERFACE) - usb_REQUEST_DEVICETOHOST_STANDARD_INTERFACE = (usb_REQUEST_DEVICETOHOST | usb_REQUEST_STANDARD | usb_REQUEST_INTERFACE) - - // CDC Class requests - usb_CDC_SET_LINE_CODING = 0x20 - usb_CDC_GET_LINE_CODING = 0x21 - usb_CDC_SET_CONTROL_LINE_STATE = 0x22 - usb_CDC_SEND_BREAK = 0x23 - - usb_CDC_V1_10 = 0x0110 - usb_CDC_COMMUNICATION_INTERFACE_CLASS = 0x02 - - usb_CDC_CALL_MANAGEMENT = 0x01 - usb_CDC_ABSTRACT_CONTROL_MODEL = 0x02 - usb_CDC_HEADER = 0x00 - usb_CDC_ABSTRACT_CONTROL_MANAGEMENT = 0x02 - usb_CDC_UNION = 0x06 - usb_CDC_CS_INTERFACE = 0x24 - usb_CDC_CS_ENDPOINT = 0x25 - usb_CDC_DATA_INTERFACE_CLASS = 0x0A - - usb_CDC_LINESTATE_DTR = 0x01 - usb_CDC_LINESTATE_RTS = 0x02 -) diff --git a/emb/machine/_usb/cdc/doc.go b/emb/machine/_usb/cdc/doc.go deleted file mode 100644 index 0a375e4..0000000 --- a/emb/machine/_usb/cdc/doc.go +++ /dev/null @@ -1,2 +0,0 @@ -// package cdc is for USB Communication Device Class devices. -package cdc diff --git a/emb/machine/_usb/cdc/usbcdc.go b/emb/machine/_usb/cdc/usbcdc.go deleted file mode 100644 index 5b5ffbf..0000000 --- a/emb/machine/_usb/cdc/usbcdc.go +++ /dev/null @@ -1,191 +0,0 @@ -package cdc - -import ( - "errors" - "machine" - "machine/usb" - "runtime/interrupt" -) - -var ( - ErrBufferEmpty = errors.New("USB-CDC buffer empty") -) - -const cdcLineInfoSize = 7 - -type cdcLineInfo struct { - dwDTERate uint32 - bCharFormat uint8 - bParityType uint8 - bDataBits uint8 - lineState uint8 -} - -// Read from the RX buffer. -func (usbcdc *USBCDC) Read(data []byte) (n int, err error) { - // check if RX buffer is empty - size := usbcdc.Buffered() - if size == 0 { - return 0, nil - } - - // Make sure we do not read more from buffer than the data slice can hold. - if len(data) < size { - size = len(data) - } - - // only read number of bytes used from buffer - for i := 0; i < size; i++ { - v, _ := usbcdc.ReadByte() - data[i] = v - } - - return size, nil -} - -// ReadByte reads a single byte from the RX buffer. -// If there is no data in the buffer, returns an error. -func (usbcdc *USBCDC) ReadByte() (byte, error) { - // check if RX buffer is empty - buf, ok := usbcdc.rxBuffer.Get() - if !ok { - return 0, ErrBufferEmpty - } - return buf, nil -} - -// Buffered returns the number of bytes currently stored in the RX buffer. -func (usbcdc *USBCDC) Buffered() int { - return int(usbcdc.rxBuffer.Used()) -} - -// Receive handles adding data to the UART's data buffer. -// Usually called by the IRQ handler for a machine. -func (usbcdc *USBCDC) Receive(data byte) { - usbcdc.rxBuffer.Put(data) -} - -// USBCDC is the USB CDC aka serial over USB interface. -type USBCDC struct { - rxBuffer *rxRingBuffer - txBuffer *txRingBuffer - waitTxc bool -} - -var ( - // USB is a USB CDC interface. - USB *USBCDC - - usbLineInfo = cdcLineInfo{115200, 0x00, 0x00, 0x08, 0x00} -) - -// Configure the USB CDC interface. The config is here for compatibility with the UART interface. -func (usbcdc *USBCDC) Configure(config machine.UARTConfig) error { - return nil -} - -// Flush flushes buffered data. -func (usbcdc *USBCDC) Flush() { - mask := interrupt.Disable() - if b, ok := usbcdc.txBuffer.Get(); ok { - machine.SendUSBInPacket(cdcEndpointIn, b) - } else { - usbcdc.waitTxc = false - } - interrupt.Restore(mask) -} - -// Write data to the USBCDC. -func (usbcdc *USBCDC) Write(data []byte) (n int, err error) { - if usbLineInfo.lineState > 0 { - mask := interrupt.Disable() - usbcdc.txBuffer.Put(data) - if !usbcdc.waitTxc { - usbcdc.waitTxc = true - usbcdc.Flush() - } - interrupt.Restore(mask) - } - return len(data), nil -} - -// WriteByte writes a byte of data to the USB CDC interface. -func (usbcdc *USBCDC) WriteByte(c byte) error { - usbcdc.Write([]byte{c}) - return nil -} - -func (usbcdc *USBCDC) DTR() bool { - return (usbLineInfo.lineState & usb_CDC_LINESTATE_DTR) > 0 -} - -func (usbcdc *USBCDC) RTS() bool { - return (usbLineInfo.lineState & usb_CDC_LINESTATE_RTS) > 0 -} - -func cdcCallbackRx(b []byte) { - for i := range b { - USB.Receive(b[i]) - } -} - -var cdcSetupBuff [cdcLineInfoSize]byte - -func cdcSetup(setup usb.Setup) bool { - if setup.BmRequestType == usb_REQUEST_DEVICETOHOST_CLASS_INTERFACE { - if setup.BRequest == usb_CDC_GET_LINE_CODING { - cdcSetupBuff[0] = byte(usbLineInfo.dwDTERate) - cdcSetupBuff[1] = byte(usbLineInfo.dwDTERate >> 8) - cdcSetupBuff[2] = byte(usbLineInfo.dwDTERate >> 16) - cdcSetupBuff[3] = byte(usbLineInfo.dwDTERate >> 24) - cdcSetupBuff[4] = byte(usbLineInfo.bCharFormat) - cdcSetupBuff[5] = byte(usbLineInfo.bParityType) - cdcSetupBuff[6] = byte(usbLineInfo.bDataBits) - - machine.SendUSBInPacket(0, cdcSetupBuff[:]) - return true - } - } - - if setup.BmRequestType == usb_REQUEST_HOSTTODEVICE_CLASS_INTERFACE { - if setup.BRequest == usb_CDC_SET_LINE_CODING { - b, err := machine.ReceiveUSBControlPacket() - if err != nil { - return false - } - - usbLineInfo.dwDTERate = uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24 - usbLineInfo.bCharFormat = b[4] - usbLineInfo.bParityType = b[5] - usbLineInfo.bDataBits = b[6] - } - - if setup.BRequest == usb_CDC_SET_CONTROL_LINE_STATE { - usbLineInfo.lineState = setup.WValueL - } - - if setup.BRequest == usb_CDC_SET_LINE_CODING || setup.BRequest == usb_CDC_SET_CONTROL_LINE_STATE { - // auto-reset into the bootloader - if usbLineInfo.dwDTERate == 1200 && usbLineInfo.lineState&usb_CDC_LINESTATE_DTR == 0 { - machine.EnterBootloader() - } else { - // TODO: cancel any reset - } - machine.SendZlp() - } - - if setup.BRequest == usb_CDC_SEND_BREAK { - // TODO: something with this value? - // breakValue = ((uint16_t)setup.wValueH << 8) | setup.wValueL; - // return false; - machine.SendZlp() - } - return true - } - return false -} - -func EnableUSBCDC() { - machine.USBCDC = New() - machine.EnableCDC(USB.Flush, cdcCallbackRx, cdcSetup) -} diff --git a/emb/machine/_usb/config.go b/emb/machine/_usb/config.go deleted file mode 100644 index 47cce9b..0000000 --- a/emb/machine/_usb/config.go +++ /dev/null @@ -1,16 +0,0 @@ -package usb - -type EndpointConfig struct { - Index uint8 - IsIn bool - TxHandler func() - RxHandler func([]byte) - DelayRxHandler func([]byte) bool - StallHandler func(Setup) bool - Type uint8 -} - -type SetupConfig struct { - Index uint8 - Handler func(Setup) bool -} diff --git a/emb/machine/_usb/descriptor/cdc.go b/emb/machine/_usb/descriptor/cdc.go deleted file mode 100644 index ec72186..0000000 --- a/emb/machine/_usb/descriptor/cdc.go +++ /dev/null @@ -1,168 +0,0 @@ -package descriptor - -const ( - cdcFunctionalHeader = 0 - cdcFunctionalCallManagement = 0x1 - cdcFunctionalACM = 0x2 - cdcFunctionalDirect = 0x3 - cdcFunctionalRinger = 0x4 - cdcFunctionalCall = 0x5 - cdcFunctionalUnion = 0x6 - cdcFunctionalCountry = 0x7 - cdcFunctionalOperational = 0x8 - cdcFunctionalUSB = 0x9 - cdcFunctionalNetwork = 0xa - cdcFunctionalProtocol = 0xb - cdcFunctionalExtension = 0xc - cdcFunctionalMulti = 0xd - cdcFunctionalCAPI = 0xe - cdcFunctionalEthernet = 0xf - cdcFunctionalATM = 0x10 -) - -var classSpecificCDCHeader = [classSpecificTypeLen]byte{ - classSpecificTypeLen, - TypeClassSpecific, - cdcFunctionalHeader, - 0x10, // - 0x1, // -} - -var ClassSpecificCDCHeader = ClassSpecificType{ - data: classSpecificCDCHeader[:], -} - -var classSpecificCDCCallManagement = [classSpecificTypeLen]byte{ - classSpecificTypeLen, - TypeClassSpecific, - cdcFunctionalCallManagement, - 0x0, // - 0x1, // -} - -var ClassSpecificCDCCallManagement = ClassSpecificType{ - data: classSpecificCDCCallManagement[:], -} - -var classSpecificCDCACM = [classSpecificTypeLen]byte{ - 4, - TypeClassSpecific, - cdcFunctionalACM, - 0x2, // -} - -var ClassSpecificCDCACM = ClassSpecificType{ - data: classSpecificCDCACM[:], -} - -var classSpecificCDCUnion = [classSpecificTypeLen]byte{ - classSpecificTypeLen, - TypeClassSpecific, - cdcFunctionalUnion, - 0x0, // - 0x1, // -} - -var ClassSpecificCDCUnion = ClassSpecificType{ - data: classSpecificCDCUnion[:], -} - -var interfaceAssociationCDC = [interfaceAssociationTypeLen]byte{ - interfaceAssociationTypeLen, - TypeInterfaceAssociation, - 0x00, // FirstInterface - 0x02, // InterfaceCount - 0x02, // FunctionClass - 0x02, // FunctionSubClass - 0x01, // FunctionProtocol - 0x00, // Function -} - -var InterfaceAssociationCDC = InterfaceAssociationType{ - data: interfaceAssociationCDC[:], -} - -var deviceCDC = [deviceTypeLen]byte{ - deviceTypeLen, - TypeDevice, - 0x00, 0x02, // USB version - 0xef, // device class - 0x02, // device subclass - 0x01, // protocol - 0x40, // maxpacketsize - 0x86, 0x28, // vendor id - 0x2d, 0x80, // product id - 0x00, 0x01, // device - 0x01, // manufacturer - 0x02, // product - 0x03, // SerialNumber - 0x01, // NumConfigurations -} - -var DeviceCDC = DeviceType{ - data: deviceCDC[:], -} - -var configurationCDC = [configurationTypeLen]byte{ - configurationTypeLen, - TypeConfiguration, - 0x4b, 0x00, // adjust length as needed - 0x02, // number of interfaces - 0x01, // configuration value - 0x00, // index to string description - 0xa0, // attributes - 0x32, // maxpower -} - -var ConfigurationCDC = ConfigurationType{ - data: configurationCDC[:], -} - -var interfaceCDCControl = [interfaceTypeLen]byte{ - interfaceTypeLen, - TypeInterface, - 0x00, // InterfaceNumber - 0x00, // AlternateSetting - 0x01, // NumEndpoints - 0x02, // InterfaceClass - 0x02, // InterfaceSubClass - 0x01, // InterfaceProtocol - 0x00, // Interface -} - -var InterfaceCDCControl = InterfaceType{ - data: interfaceCDCControl[:], -} - -var interfaceCDCData = [interfaceTypeLen]byte{ - interfaceTypeLen, - TypeInterface, - 0x01, // InterfaceNumber - 0x00, // AlternateSetting - 0x02, // NumEndpoints - 0x0a, // InterfaceClass - 0x00, // InterfaceSubClass - 0x00, // InterfaceProtocol - 0x00, // Interface -} - -var InterfaceCDCData = InterfaceType{ - data: interfaceCDCData[:], -} - -var CDC = Descriptor{ - Device: DeviceCDC.Bytes(), - Configuration: Append([][]byte{ - ConfigurationCDC.Bytes(), - InterfaceAssociationCDC.Bytes(), - InterfaceCDCControl.Bytes(), - ClassSpecificCDCHeader.Bytes(), - ClassSpecificCDCCallManagement.Bytes(), - ClassSpecificCDCACM.Bytes(), - ClassSpecificCDCUnion.Bytes(), - EndpointEP1IN.Bytes(), - InterfaceCDCData.Bytes(), - EndpointEP2OUT.Bytes(), - EndpointEP3IN.Bytes(), - }), -} diff --git a/emb/machine/_usb/descriptor/classspecific.go b/emb/machine/_usb/descriptor/classspecific.go deleted file mode 100644 index d8ea937..0000000 --- a/emb/machine/_usb/descriptor/classspecific.go +++ /dev/null @@ -1,17 +0,0 @@ -package descriptor - -const ( - classSpecificTypeLen = 5 -) - -type ClassSpecificType struct { - data []byte -} - -func (d ClassSpecificType) Bytes() []byte { - return d.data[:d.data[0]] -} - -func (d ClassSpecificType) Length(v uint8) { - d.data[0] = byte(v) -} diff --git a/emb/machine/_usb/descriptor/configuration.go b/emb/machine/_usb/descriptor/configuration.go deleted file mode 100644 index efb9ab1..0000000 --- a/emb/machine/_usb/descriptor/configuration.go +++ /dev/null @@ -1,49 +0,0 @@ -package descriptor - -import ( - "internal/binary" -) - -const ( - configurationTypeLen = 9 -) - -type ConfigurationType struct { - data []byte -} - -func (d ConfigurationType) Bytes() []byte { - return d.data -} - -func (d ConfigurationType) Length(v uint8) { - d.data[0] = byte(v) -} - -func (d ConfigurationType) Type(v uint8) { - d.data[1] = byte(v) -} - -func (d ConfigurationType) TotalLength(v uint16) { - binary.LittleEndian.PutUint16(d.data[2:4], v) -} - -func (d ConfigurationType) NumInterfaces(v uint8) { - d.data[4] = byte(v) -} - -func (d ConfigurationType) ConfigurationValue(v uint8) { - d.data[5] = byte(v) -} - -func (d ConfigurationType) Configuration(v uint8) { - d.data[6] = byte(v) -} - -func (d ConfigurationType) Attributes(v uint8) { - d.data[7] = byte(v) -} - -func (d ConfigurationType) MaxPower(v uint8) { - d.data[8] = byte(v) -} diff --git a/emb/machine/_usb/descriptor/descriptor.go b/emb/machine/_usb/descriptor/descriptor.go deleted file mode 100644 index 852ddab..0000000 --- a/emb/machine/_usb/descriptor/descriptor.go +++ /dev/null @@ -1,63 +0,0 @@ -package descriptor - -import ( - "runtime/volatile" -) - -const ( - TypeDevice = 0x1 - TypeConfiguration = 0x2 - TypeString = 0x3 - TypeInterface = 0x4 - TypeEndpoint = 0x5 - TypeDeviceQualifier = 0x6 - TypeInterfaceAssociation = 0xb - TypeClassHID = 0x21 - TypeHIDReport = 0x22 - TypeClassSpecific = 0x24 - TypeClassSpecificEndpoint = 0x25 -) - -// DeviceDescBank is the USB device endpoint . -type DeviceDescBank struct { - ADDR volatile.Register32 - PCKSIZE volatile.Register32 - EXTREG volatile.Register16 - STATUS_BK volatile.Register8 - _reserved [5]volatile.Register8 -} - -type Device struct { - DeviceDescBank [2]DeviceDescBank -} - -type Descriptor struct { - Device []byte - Configuration []byte - HID map[uint16][]byte -} - -func (d *Descriptor) Configure(idVendor, idProduct uint16) { - dev := DeviceType{d.Device} - dev.VendorID(idVendor) - dev.ProductID(idProduct) - - conf := ConfigurationType{d.Configuration} - conf.TotalLength(uint16(len(d.Configuration))) -} - -func Append[T any](slices [][]T) []T { - var size, pos int - - for _, s := range slices { - size += len(s) - } - - result := make([]T, size) - - for _, s := range slices { - pos += copy(result[pos:], s) - } - - return result -} diff --git a/emb/machine/_usb/descriptor/device.go b/emb/machine/_usb/descriptor/device.go deleted file mode 100644 index 0c3ee92..0000000 --- a/emb/machine/_usb/descriptor/device.go +++ /dev/null @@ -1,73 +0,0 @@ -package descriptor - -import ( - "internal/binary" -) - -const ( - deviceTypeLen = 18 -) - -type DeviceType struct { - data []byte -} - -func (d DeviceType) Bytes() []byte { - return d.data -} - -func (d DeviceType) Length(v uint8) { - d.data[0] = byte(v) -} - -func (d DeviceType) Type(v uint8) { - d.data[1] = byte(v) -} - -func (d DeviceType) USB(v uint16) { - binary.LittleEndian.PutUint16(d.data[2:4], v) -} - -func (d DeviceType) DeviceClass(v uint8) { - d.data[4] = byte(v) -} - -func (d DeviceType) DeviceSubClass(v uint8) { - d.data[5] = byte(v) -} - -func (d DeviceType) DeviceProtocol(v uint8) { - d.data[6] = byte(v) -} - -func (d DeviceType) MaxPacketSize0(v uint8) { - d.data[7] = byte(v) -} - -func (d DeviceType) VendorID(v uint16) { - binary.LittleEndian.PutUint16(d.data[8:10], v) -} - -func (d DeviceType) ProductID(v uint16) { - binary.LittleEndian.PutUint16(d.data[10:12], v) -} - -func (d DeviceType) Device(v uint16) { - binary.LittleEndian.PutUint16(d.data[12:14], v) -} - -func (d DeviceType) Manufacturer(v uint8) { - d.data[14] = byte(v) -} - -func (d DeviceType) Product(v uint8) { - d.data[15] = byte(v) -} - -func (d DeviceType) SerialNumber(v uint8) { - d.data[16] = byte(v) -} - -func (d DeviceType) NumConfigurations(v uint8) { - d.data[17] = byte(v) -} diff --git a/emb/machine/_usb/descriptor/doc.go b/emb/machine/_usb/descriptor/doc.go deleted file mode 100644 index f35a768..0000000 --- a/emb/machine/_usb/descriptor/doc.go +++ /dev/null @@ -1,3 +0,0 @@ -// package descriptor is for the USB descriptor definitions. -// For the actual implementations, see the individual packages. -package descriptor diff --git a/emb/machine/_usb/descriptor/endpoint.go b/emb/machine/_usb/descriptor/endpoint.go deleted file mode 100644 index 57a1706..0000000 --- a/emb/machine/_usb/descriptor/endpoint.go +++ /dev/null @@ -1,156 +0,0 @@ -package descriptor - -import ( - "internal/binary" -) - -/* Endpoint Descriptor -USB 2.0 Specification: 9.6.6 Endpoint -*/ - -const ( - TransferTypeControl uint8 = iota - TransferTypeIsochronous - TransferTypeBulk - TransferTypeInterrupt -) - -var endpointEP1IN = [endpointTypeLen]byte{ - endpointTypeLen, - TypeEndpoint, - 0x81, // EndpointAddress - 0x03, // Attributes - 0x10, // MaxPacketSizeL - 0x00, // MaxPacketSizeH - 0x10, // Interval -} - -var EndpointEP1IN = EndpointType{ - data: endpointEP1IN[:], -} - -var endpointEP2OUT = [endpointTypeLen]byte{ - endpointTypeLen, - TypeEndpoint, - 0x02, // EndpointAddress - 0x02, // Attributes - 0x40, // MaxPacketSizeL - 0x00, // MaxPacketSizeH - 0x00, // Interval -} - -var EndpointEP2OUT = EndpointType{ - data: endpointEP2OUT[:], -} - -var endpointEP3IN = [endpointTypeLen]byte{ - endpointTypeLen, - TypeEndpoint, - 0x83, // EndpointAddress - 0x02, // Attributes - 0x40, // MaxPacketSizeL - 0x00, // MaxPacketSizeH - 0x00, // Interval -} - -var EndpointEP3IN = EndpointType{ - data: endpointEP3IN[:], -} - -var endpointEP4IN = [endpointTypeLen]byte{ - endpointTypeLen, - TypeEndpoint, - 0x84, // EndpointAddress - 0x03, // Attributes - 0x40, // MaxPacketSizeL - 0x00, // MaxPacketSizeH - 0x01, // Interval -} - -var EndpointEP4IN = EndpointType{ - data: endpointEP4IN[:], -} - -var endpointEP5OUT = [endpointTypeLen]byte{ - endpointTypeLen, - TypeEndpoint, - 0x05, // EndpointAddress - 0x03, // Attributes - 0x40, // MaxPacketSizeL - 0x00, // MaxPacketSizeH - 0x01, // Interval -} - -var EndpointEP5OUT = EndpointType{ - data: endpointEP5OUT[:], -} - -// Mass Storage Class bulk in endpoint -var endpointMSCIN = [endpointTypeLen]byte{ - endpointTypeLen, - TypeEndpoint, - 0x86, // EndpointAddress - TransferTypeBulk, // Attributes - 0x40, // MaxPacketSizeL (64 bytes) - 0x00, // MaxPacketSizeH - 0x00, // Interval -} - -var EndpointMSCIN = EndpointType{ - data: endpointMSCIN[:], -} - -// Mass Storage Class bulk out endpoint -var endpointMSCOUT = [endpointTypeLen]byte{ - endpointTypeLen, - TypeEndpoint, - 0x07, // EndpointAddress - TransferTypeBulk, // Attributes - 0x40, // MaxPacketSizeL (64 bytes) - 0x00, // MaxPacketSizeH - 0x00, // Interval -} - -var EndpointMSCOUT = EndpointType{ - data: endpointMSCOUT[:], -} - -const ( - endpointTypeLen = 7 -) - -type EndpointType struct { - data []byte -} - -func (d EndpointType) Bytes() []byte { - return d.data -} - -func (d EndpointType) Length(v uint8) { - d.data[0] = byte(v) -} - -func (d EndpointType) Type(v uint8) { - d.data[1] = byte(v) -} - -func (d EndpointType) EndpointAddress(v uint8) { - d.data[2] = byte(v) -} - -func (d EndpointType) Attributes(v uint8) { - d.data[3] = byte(v) -} - -func (d EndpointType) MaxPacketSize(v uint16) { - binary.LittleEndian.PutUint16(d.data[4:6], v) -} - -func (d EndpointType) Interval(v uint8) { - d.data[6] = byte(v) -} - -func (d EndpointType) GetMaxPacketSize() uint16 { - return binary.LittleEndian.Uint16(d.data[4:6]) -} diff --git a/emb/machine/_usb/descriptor/hid.go b/emb/machine/_usb/descriptor/hid.go deleted file mode 100644 index 06b9801..0000000 --- a/emb/machine/_usb/descriptor/hid.go +++ /dev/null @@ -1,216 +0,0 @@ -package descriptor - -import ( - "errors" - "internal/binary" - "internal/bytealg" -) - -var configurationCDCHID = [configurationTypeLen]byte{ - configurationTypeLen, - TypeConfiguration, - 0x64, 0x00, // adjust length as needed - 0x03, // number of interfaces - 0x01, // configuration value - 0x00, // index to string description - 0xa0, // attributes - 0x32, // maxpower -} - -var ConfigurationCDCHID = ConfigurationType{ - data: configurationCDCHID[:], -} - -var interfaceHID = [interfaceTypeLen]byte{ - interfaceTypeLen, - TypeInterface, - 0x02, // InterfaceNumber - 0x00, // AlternateSetting - 0x02, // NumEndpoints - 0x03, // InterfaceClass - 0x00, // InterfaceSubClass - 0x00, // InterfaceProtocol - 0x00, // Interface -} - -var InterfaceHID = InterfaceType{ - data: interfaceHID[:], -} - -const ( - ClassHIDTypeLen = 9 -) - -type ClassHIDType struct { - data []byte -} - -func (d ClassHIDType) Bytes() []byte { - return d.data[:] -} - -func (d ClassHIDType) Length(v uint8) { - d.data[0] = byte(v) -} - -func (d ClassHIDType) Type(v uint8) { - d.data[1] = byte(v) -} - -func (d ClassHIDType) HID(v uint16) { - binary.LittleEndian.PutUint16(d.data[2:4], v) -} - -func (d ClassHIDType) CountryCode(v uint8) { - d.data[4] = byte(v) -} - -func (d ClassHIDType) NumDescriptors(v uint8) { - d.data[5] = byte(v) -} - -func (d ClassHIDType) ClassType(v uint8) { - d.data[6] = byte(v) -} - -func (d ClassHIDType) ClassLength(v uint16) { - binary.LittleEndian.PutUint16(d.data[7:9], v) -} - -var errNoClassHIDFound = errors.New("no classHID found") - -// FindClassHIDType tries to find the ClassHID class in the descriptor. -func FindClassHIDType(des, class []byte) (ClassHIDType, error) { - if len(des) < ClassHIDTypeLen || len(class) == 0 { - return ClassHIDType{}, errNoClassHIDFound - } - - // search only for ClassHIDType without the ClassLength, - // in case it has already been set. - idx := bytealg.Index(des, class[:ClassHIDTypeLen-2]) - if idx == -1 { - return ClassHIDType{}, errNoClassHIDFound - } - - return ClassHIDType{data: des[idx : idx+ClassHIDTypeLen]}, nil -} - -var classHID = [ClassHIDTypeLen]byte{ - ClassHIDTypeLen, - TypeClassHID, - 0x11, // HID version L - 0x01, // HID version H - 0x00, // CountryCode - 0x01, // NumDescriptors - 0x22, // ClassType - 0x91, // ClassLength L - 0x00, // ClassLength H -} - -var ClassHID = ClassHIDType{ - data: classHID[:], -} - -var CDCHID = Descriptor{ - Device: DeviceCDC.Bytes(), - Configuration: Append([][]byte{ - ConfigurationCDCHID.Bytes(), - InterfaceAssociationCDC.Bytes(), - InterfaceCDCControl.Bytes(), - ClassSpecificCDCHeader.Bytes(), - ClassSpecificCDCACM.Bytes(), - ClassSpecificCDCUnion.Bytes(), - ClassSpecificCDCCallManagement.Bytes(), - EndpointEP1IN.Bytes(), - InterfaceCDCData.Bytes(), - EndpointEP2OUT.Bytes(), - EndpointEP3IN.Bytes(), - InterfaceHID.Bytes(), - ClassHID.Bytes(), - EndpointEP4IN.Bytes(), - EndpointEP5OUT.Bytes(), - }), - HID: map[uint16][]byte{ - 2: Append([][]byte{ // Update ClassLength in classHID whenever the array length is modified! - HIDUsagePageGenericDesktop, - HIDUsageDesktopKeyboard, - HIDCollectionApplication, - HIDReportID(2), - - HIDUsagePageKeyboard, - HIDUsageMinimum(224), - HIDUsageMaximum(231), - HIDLogicalMinimum(0), - HIDLogicalMaximum(1), - HIDReportSize(1), - HIDReportCount(8), - HIDInputDataVarAbs, - HIDReportCount(1), - HIDReportSize(8), - HIDInputConstVarAbs, - HIDReportCount(3), - HIDReportSize(1), - HIDUsagePageLED, - HIDUsageMinimum(1), - HIDUsageMaximum(3), - HIDOutputDataVarAbs, - HIDReportCount(5), - HIDReportSize(1), - HIDOutputConstVarAbs, - HIDReportCount(6), - HIDReportSize(8), - HIDLogicalMinimum(0), - HIDLogicalMaximum(255), - - HIDUsagePageKeyboard, - HIDUsageMinimum(0), - HIDUsageMaximum(255), - HIDInputDataAryAbs, - HIDCollectionEnd, - - HIDUsagePageGenericDesktop, - HIDUsageDesktopMouse, - HIDCollectionApplication, - HIDUsageDesktopPointer, - HIDCollectionPhysical, - HIDReportID(1), - - HIDUsagePageButton, - HIDUsageMinimum(1), - HIDUsageMaximum(5), - HIDLogicalMinimum(0), - HIDLogicalMaximum(1), - HIDReportCount(5), - HIDReportSize(1), - HIDInputDataVarAbs, - HIDReportCount(1), - HIDReportSize(3), - HIDInputConstVarAbs, - - HIDUsagePageGenericDesktop, - HIDUsageDesktopX, - HIDUsageDesktopY, - HIDUsageDesktopWheel, - HIDLogicalMinimum(-127), - HIDLogicalMaximum(127), - HIDReportSize(8), - HIDReportCount(3), - HIDInputDataVarRel, - HIDCollectionEnd, - HIDCollectionEnd, - - HIDUsagePageConsumer, - HIDUsageConsumerControl, - HIDCollectionApplication, - HIDReportID(3), - HIDLogicalMinimum(0), - HIDLogicalMaximum(8191), - HIDUsageMinimum(0), - HIDUsageMaximum(0x1FFF), - HIDReportSize(16), - HIDReportCount(1), - HIDInputDataAryAbs, - HIDCollectionEnd, - }), - }, -} diff --git a/emb/machine/_usb/descriptor/hidreport.go b/emb/machine/_usb/descriptor/hidreport.go deleted file mode 100644 index 625578f..0000000 --- a/emb/machine/_usb/descriptor/hidreport.go +++ /dev/null @@ -1,220 +0,0 @@ -package descriptor - -import "math" - -const ( - hidUsagePage = 0x04 - hidUsage = 0x08 - hidLogicalMinimum = 0x14 - hidLogicalMaximum = 0x24 - hidUsageMinimum = 0x18 - hidUsageMaximum = 0x28 - hidPhysicalMinimum = 0x34 - hidPhysicalMaximum = 0x44 - hidUnitExponent = 0x54 - hidUnit = 0x64 - hidCollection = 0xA0 - hidInput = 0x80 - hidOutput = 0x90 - hidReportSize = 0x74 - hidReportCount = 0x94 - hidReportID = 0x84 -) - -const ( - hidSizeValue0 = 0x00 - hidSizeValue1 = 0x01 - hidSizeValue2 = 0x02 - hidSizeValue4 = 0x03 -) - -var ( - HIDUsagePageGenericDesktop = HIDUsagePage(0x01) - HIDUsagePageSimulationControls = HIDUsagePage(0x02) - HIDUsagePageVRControls = HIDUsagePage(0x03) - HIDUsagePageSportControls = HIDUsagePage(0x04) - HIDUsagePageGameControls = HIDUsagePage(0x05) - HIDUsagePageGenericControls = HIDUsagePage(0x06) - HIDUsagePageKeyboard = HIDUsagePage(0x07) - HIDUsagePageLED = HIDUsagePage(0x08) - HIDUsagePageButton = HIDUsagePage(0x09) - HIDUsagePageOrdinal = HIDUsagePage(0x0A) - HIDUsagePageTelephony = HIDUsagePage(0x0B) - HIDUsagePageConsumer = HIDUsagePage(0x0C) - HIDUsagePageDigitizers = HIDUsagePage(0x0D) - HIDUsagePageHaptics = HIDUsagePage(0x0E) - HIDUsagePagePhysicalInput = HIDUsagePage(0x0F) - HIDUsagePageUnicode = HIDUsagePage(0x10) - HIDUsagePageSoC = HIDUsagePage(0x11) - HIDUsagePageEyeHeadTrackers = HIDUsagePage(0x12) - HIDUsagePageAuxDisplay = HIDUsagePage(0x14) - HIDUsagePageSensors = HIDUsagePage(0x20) - HIDUsagePageMedicalInstrument = HIDUsagePage(0x40) - HIDUsagePageBrailleDisplay = HIDUsagePage(0x41) - HIDUsagePageLighting = HIDUsagePage(0x59) - HIDUsagePageMonitor = HIDUsagePage(0x80) - HIDUsagePageMonitorEnum = HIDUsagePage(0x81) - HIDUsagePageVESA = HIDUsagePage(0x82) - HIDUsagePagePower = HIDUsagePage(0x84) - HIDUsagePageBatterySystem = HIDUsagePage(0x85) - HIDUsagePageBarcodeScanner = HIDUsagePage(0x8C) - HIDUsagePageScales = HIDUsagePage(0x8D) - HIDUsagePageMagneticStripe = HIDUsagePage(0x8E) - HIDUsagePageCameraControl = HIDUsagePage(0x90) - HIDUsagePageArcade = HIDUsagePage(0x91) - HIDUsagePageGaming = HIDUsagePage(0x92) -) - -var ( - HIDUsageDesktopPointer = HIDUsage(0x01) - HIDUsageDesktopMouse = HIDUsage(0x02) - HIDUsageDesktopJoystick = HIDUsage(0x04) - HIDUsageDesktopGamepad = HIDUsage(0x05) - HIDUsageDesktopKeyboard = HIDUsage(0x06) - HIDUsageDesktopKeypad = HIDUsage(0x07) - HIDUsageDesktopMultiaxis = HIDUsage(0x08) - HIDUsageDesktopTablet = HIDUsage(0x09) - HIDUsageDesktopWaterCooling = HIDUsage(0x0A) - HIDUsageDesktopChassis = HIDUsage(0x0B) - HIDUsageDesktopWireless = HIDUsage(0x0C) - HIDUsageDesktopPortable = HIDUsage(0x0D) - HIDUsageDesktopSystemMultiaxis = HIDUsage(0x0E) - HIDUsageDesktopSpatial = HIDUsage(0x0F) - HIDUsageDesktopAssistive = HIDUsage(0x10) - HIDUsageDesktopDock = HIDUsage(0x11) - HIDUsageDesktopDockable = HIDUsage(0x12) - HIDUsageDesktopCallState = HIDUsage(0x13) - HIDUsageDesktopX = HIDUsage(0x30) - HIDUsageDesktopY = HIDUsage(0x31) - HIDUsageDesktopZ = HIDUsage(0x32) - HIDUsageDesktopRx = HIDUsage(0x33) - HIDUsageDesktopRy = HIDUsage(0x34) - HIDUsageDesktopRz = HIDUsage(0x35) - HIDUsageDesktopSlider = HIDUsage(0x36) - HIDUsageDesktopDial = HIDUsage(0x37) - HIDUsageDesktopWheel = HIDUsage(0x38) - HIDUsageDesktopHatSwitch = HIDUsage(0x39) - HIDUsageDesktopCountedBuffer = HIDUsage(0x3A) -) - -var ( - HIDUsageConsumerControl = HIDUsage(0x01) - HIDUsageConsumerNumericKeypad = HIDUsage(0x02) - HIDUsageConsumerProgrammableButtons = HIDUsage(0x03) - HIDUsageConsumerMicrophone = HIDUsage(0x04) - HIDUsageConsumerHeadphone = HIDUsage(0x05) - HIDUsageConsumerGraphicEqualizer = HIDUsage(0x06) -) - -var ( - HIDCollectionPhysical = HIDCollection(0x00) - HIDCollectionApplication = HIDCollection(0x01) - HIDCollectionEnd = []byte{0xC0} -) - -var ( - // Input (Data,Ary,Abs), Key arrays (6 bytes) - HIDInputDataAryAbs = HIDInput(0x00) - - // Input (Data, Variable, Absolute), Modifier byte - HIDInputDataVarAbs = HIDInput(0x02) - - // Input (Const,Var,Abs), Modifier byte - HIDInputConstVarAbs = HIDInput(0x03) - - // Input (Data, Variable, Relative), 2 position bytes (X & Y) - HIDInputDataVarRel = HIDInput(0x06) - - // Output (Data, Variable, Absolute), Modifier byte - HIDOutputDataVarAbs = HIDOutput(0x02) - - // Output (Const, Variable, Absolute), Modifier byte - HIDOutputConstVarAbs = HIDOutput(0x03) -) - -func hidShortItem(tag byte, value uint32) []byte { - switch { - case value <= math.MaxUint8: - return []byte{tag | hidSizeValue1, byte(value)} - case value <= math.MaxUint16: - return []byte{tag | hidSizeValue2, byte(value), byte(value >> 8)} - default: - return []byte{tag | hidSizeValue4, byte(value), byte(value >> 8), byte(value >> 16), byte(value >> 24)} - } -} - -func hidShortItemSigned(tag byte, value int32) []byte { - switch { - case math.MinInt8 <= value && value <= math.MaxInt8: - return []byte{tag | hidSizeValue1, byte(value)} - case math.MinInt16 <= value && value <= math.MaxInt16: - return []byte{tag | hidSizeValue2, byte(value), byte(value >> 8)} - default: - return []byte{tag | hidSizeValue4, byte(value), byte(value >> 8), byte(value >> 16), byte(value >> 24)} - } -} - -func HIDReportSize(size int) []byte { - return hidShortItem(hidReportSize, uint32(size)) -} - -func HIDReportCount(count int) []byte { - return hidShortItem(hidReportCount, uint32(count)) -} - -func HIDReportID(id int) []byte { - return hidShortItem(hidReportID, uint32(id)) -} - -func HIDLogicalMinimum(min int) []byte { - return hidShortItemSigned(hidLogicalMinimum, int32(min)) -} - -func HIDLogicalMaximum(max int) []byte { - return hidShortItemSigned(hidLogicalMaximum, int32(max)) -} - -func HIDUsageMinimum(min int) []byte { - return hidShortItem(hidUsageMinimum, uint32(min)) -} - -func HIDUsageMaximum(max int) []byte { - return hidShortItem(hidUsageMaximum, uint32(max)) -} - -func HIDPhysicalMinimum(min int) []byte { - return hidShortItemSigned(hidPhysicalMinimum, int32(min)) -} - -func HIDPhysicalMaximum(max int) []byte { - return hidShortItemSigned(hidPhysicalMaximum, int32(max)) -} - -func HIDUnitExponent(exp int) []byte { - // 4 Bit two's complement - return hidShortItem(hidUnitExponent, uint32(exp&0xF)) -} - -func HIDUnit(unit uint32) []byte { - return hidShortItem(hidUnit, unit) -} - -func HIDUsagePage(id uint16) []byte { - return hidShortItem(hidUsagePage, uint32(id)) -} - -func HIDUsage(id uint32) []byte { - return hidShortItem(hidUsage, id) -} - -func HIDCollection(id uint32) []byte { - return hidShortItem(hidCollection, id) -} - -func HIDInput(flags uint32) []byte { - return hidShortItem(hidInput, flags) -} - -func HIDOutput(flags uint32) []byte { - return hidShortItem(hidOutput, flags) -} diff --git a/emb/machine/_usb/descriptor/interface.go b/emb/machine/_usb/descriptor/interface.go deleted file mode 100644 index 52f537f..0000000 --- a/emb/machine/_usb/descriptor/interface.go +++ /dev/null @@ -1,49 +0,0 @@ -package descriptor - -const ( - interfaceTypeLen = 9 -) - -type InterfaceType struct { - data []byte -} - -func (d InterfaceType) Bytes() []byte { - return d.data -} - -func (d InterfaceType) Length(v uint8) { - d.data[0] = byte(v) -} - -func (d InterfaceType) Type(v uint8) { - d.data[1] = byte(v) -} - -func (d InterfaceType) InterfaceNumber(v uint8) { - d.data[2] = byte(v) -} - -func (d InterfaceType) AlternateSetting(v uint8) { - d.data[3] = byte(v) -} - -func (d InterfaceType) NumEndpoints(v uint8) { - d.data[4] = byte(v) -} - -func (d InterfaceType) InterfaceClass(v uint8) { - d.data[5] = byte(v) -} - -func (d InterfaceType) InterfaceSubClass(v uint8) { - d.data[6] = byte(v) -} - -func (d InterfaceType) InterfaceProtocol(v uint8) { - d.data[7] = byte(v) -} - -func (d InterfaceType) Interface(v uint8) { - d.data[8] = byte(v) -} diff --git a/emb/machine/_usb/descriptor/interfaceassociation.go b/emb/machine/_usb/descriptor/interfaceassociation.go deleted file mode 100644 index f928086..0000000 --- a/emb/machine/_usb/descriptor/interfaceassociation.go +++ /dev/null @@ -1,45 +0,0 @@ -package descriptor - -const ( - interfaceAssociationTypeLen = 8 -) - -type InterfaceAssociationType struct { - data []byte -} - -func (d InterfaceAssociationType) Bytes() []byte { - return d.data -} - -func (d InterfaceAssociationType) Length(v uint8) { - d.data[0] = byte(v) -} - -func (d InterfaceAssociationType) Type(v uint8) { - d.data[1] = byte(v) -} - -func (d InterfaceAssociationType) FirstInterface(v uint8) { - d.data[2] = byte(v) -} - -func (d InterfaceAssociationType) InterfaceCount(v uint8) { - d.data[3] = byte(v) -} - -func (d InterfaceAssociationType) FunctionClass(v uint8) { - d.data[4] = byte(v) -} - -func (d InterfaceAssociationType) FunctionSubClass(v uint8) { - d.data[5] = byte(v) -} - -func (d InterfaceAssociationType) FunctionProtocol(v uint8) { - d.data[6] = byte(v) -} - -func (d InterfaceAssociationType) Function(v uint8) { - d.data[7] = byte(v) -} diff --git a/emb/machine/_usb/descriptor/joystick.go b/emb/machine/_usb/descriptor/joystick.go deleted file mode 100644 index 65756e0..0000000 --- a/emb/machine/_usb/descriptor/joystick.go +++ /dev/null @@ -1,144 +0,0 @@ -package descriptor - -var deviceJoystick = [deviceTypeLen]byte{ - deviceTypeLen, - TypeDevice, - 0x00, 0x02, // USB version - 0xef, // device class - 0x02, // subclass - 0x01, // protocol - 0x40, // maxpacketsize - 0x41, 0x23, // vendor id - 0x36, 0x80, // product id - 0x00, 0x01, // device - 0x01, // manufacturer - 0x02, // product - 0x03, // SerialNumber - 0x01, // NumConfigurations -} - -var DeviceJoystick = DeviceType{ - data: deviceJoystick[:], -} - -var configurationCDCJoystick = [configurationTypeLen]byte{ - configurationTypeLen, - TypeConfiguration, - 0x6b, 0x00, // adjust length as needed - 0x03, // number of interfaces - 0x01, // configuration value - 0x00, // index to string description - 0xa0, // attributes - 0xfa, // maxpower -} - -var ConfigurationCDCJoystick = ConfigurationType{ - data: configurationCDCJoystick[:], -} - -var interfaceHIDJoystick = [interfaceTypeLen]byte{ - interfaceTypeLen, - TypeInterface, - 0x02, // InterfaceNumber - 0x00, // AlternateSetting - 0x02, // NumEndpoints - 0x03, // InterfaceClass - 0x00, // InterfaceSubClass - 0x00, // InterfaceProtocol - 0x00, // Interface -} - -var InterfaceHIDJoystick = InterfaceType{ - data: interfaceHIDJoystick[:], -} - -var classHIDJoystick = [ClassHIDTypeLen]byte{ - ClassHIDTypeLen, - TypeClassHID, - 0x11, // HID version L - 0x01, // HID version H - 0x00, // CountryCode - 0x01, // NumDescriptors - 0x22, // ClassType - 0x00, // ClassLength L - 0x00, // ClassLength H -} - -var ClassHIDJoystick = ClassHIDType{ - data: classHIDJoystick[:], -} - -var JoystickDefaultHIDReport = Append([][]byte{ - HIDUsagePageGenericDesktop, - HIDUsageDesktopJoystick, - HIDCollectionApplication, - HIDReportID(1), - HIDUsagePageButton, - HIDUsageMinimum(1), - HIDUsageMaximum(16), - HIDLogicalMinimum(0), - HIDLogicalMaximum(1), - HIDReportSize(1), - HIDReportCount(16), - HIDUnitExponent(0), - HIDUnit(0), - HIDInputDataVarAbs, - - HIDUsagePageGenericDesktop, - HIDUsageDesktopHatSwitch, - HIDLogicalMinimum(0), - HIDLogicalMaximum(7), - HIDPhysicalMinimum(0), - HIDPhysicalMaximum(315), - HIDUnit(0x14), - HIDReportCount(1), - HIDReportSize(4), - HIDInputDataVarAbs, - HIDUsageDesktopHatSwitch, - HIDReportCount(1), - HIDReportSize(4), - HIDInputConstVarAbs, - HIDUsageDesktopPointer, - HIDLogicalMinimum(-32767), - HIDLogicalMaximum(32767), - HIDPhysicalMinimum(0), - HIDPhysicalMaximum(0), - HIDUnit(0), - HIDReportCount(6), - HIDReportSize(16), - HIDCollectionPhysical, - HIDUsageDesktopX, - HIDUsageDesktopY, - HIDUsageDesktopZ, - HIDUsageDesktopRx, - HIDUsageDesktopRy, - HIDUsageDesktopRz, - HIDInputDataVarAbs, - HIDCollectionEnd, - HIDCollectionEnd, -}) - -// CDCJoystick requires that you append the JoystickDescriptor -// to the Configuration before using. This is in order to support -// custom configurations. -var CDCJoystick = Descriptor{ - Device: DeviceJoystick.Bytes(), - Configuration: Append([][]byte{ - ConfigurationCDCJoystick.Bytes(), - InterfaceAssociationCDC.Bytes(), - InterfaceCDCControl.Bytes(), - ClassSpecificCDCHeader.Bytes(), - ClassSpecificCDCACM.Bytes(), - ClassSpecificCDCUnion.Bytes(), - ClassSpecificCDCCallManagement.Bytes(), - EndpointEP1IN.Bytes(), - InterfaceCDCData.Bytes(), - EndpointEP2OUT.Bytes(), - EndpointEP3IN.Bytes(), - InterfaceHIDJoystick.Bytes(), - ClassHIDJoystick.Bytes(), - EndpointEP4IN.Bytes(), - EndpointEP5OUT.Bytes(), - }), - HID: map[uint16][]byte{}, -} diff --git a/emb/machine/_usb/descriptor/midi.go b/emb/machine/_usb/descriptor/midi.go deleted file mode 100644 index fad81f3..0000000 --- a/emb/machine/_usb/descriptor/midi.go +++ /dev/null @@ -1,249 +0,0 @@ -package descriptor - -var interfaceAssociationMIDI = [interfaceAssociationTypeLen]byte{ - interfaceAssociationTypeLen, - TypeInterfaceAssociation, - 0x02, // EndpointAddress - 0x02, // Attributes - 0x01, // MaxPacketSizeL - 0x01, // MaxPacketSizeH - 0x00, // Interval - 0x00, // Interval -} - -var InterfaceAssociationMIDI = InterfaceAssociationType{ - data: interfaceAssociationMIDI[:], -} - -var interfaceAudio = [interfaceTypeLen]byte{ - interfaceTypeLen, - TypeInterface, - 0x02, // InterfaceNumber - 0x00, // AlternateSetting - 0x00, // NumEndpoints - 0x01, // InterfaceClass - 0x01, // InterfaceSubClass - 0x00, // InterfaceProtocol - 0x00, // Interface -} - -var InterfaceAudio = InterfaceType{ - data: interfaceAudio[:], -} - -var interfaceMIDIStreaming = [interfaceTypeLen]byte{ - interfaceTypeLen, - TypeInterface, - 0x03, // InterfaceNumber - 0x00, // AlternateSetting - 0x02, // NumEndpoints - 0x01, // InterfaceClass - 0x03, // InterfaceSubClass - 0x00, // InterfaceProtocol - 0x00, // Interface -} - -var InterfaceMIDIStreaming = InterfaceType{ - data: interfaceMIDIStreaming[:], -} - -const classSpecificAudioTypeLen = 9 - -var classSpecificAudioInterface = [classSpecificAudioTypeLen]byte{ - classSpecificAudioTypeLen, - TypeClassSpecific, - 0x01, - 0x00, // - 0x01, // - 0x09, - 0x00, - 0x01, - 0x03, -} - -var ClassSpecificAudioInterface = ClassSpecificType{ - data: classSpecificAudioInterface[:], -} - -const classSpecificMIDIHeaderLen = 7 - -var classSpecificMIDIHeader = [classSpecificMIDIHeaderLen]byte{ - classSpecificMIDIHeaderLen, - TypeClassSpecific, - 0x01, - 0x00, // - 0x01, // - 0x41, - 0x00, -} - -var ClassSpecificMIDIHeader = ClassSpecificType{ - data: classSpecificMIDIHeader[:], -} - -const classSpecificMIDIInJackLen = 6 - -var classSpecificMIDIInJack1 = [classSpecificMIDIInJackLen]byte{ - classSpecificMIDIInJackLen, - TypeClassSpecific, - 0x02, // MIDI In jack - 0x01, // Jack type (embedded) - 0x01, // Jack ID - 0x00, // iJack -} - -var ClassSpecificMIDIInJack1 = ClassSpecificType{ - data: classSpecificMIDIInJack1[:], -} - -var classSpecificMIDIInJack2 = [classSpecificMIDIInJackLen]byte{ - classSpecificMIDIInJackLen, - TypeClassSpecific, - 0x02, // MIDI In jack - 0x02, // Jack type (external) - 0x02, // Jack ID - 0x00, // iJack -} - -var ClassSpecificMIDIInJack2 = ClassSpecificType{ - data: classSpecificMIDIInJack2[:], -} - -const classSpecificMIDIOutJackLen = 9 - -var classSpecificMIDIOutJack1 = [classSpecificMIDIOutJackLen]byte{ - classSpecificMIDIOutJackLen, - TypeClassSpecific, - 0x03, // MIDI Out jack - 0x01, // Jack type (embedded) - 0x03, // Jack ID - 0x01, // number of input pins - 0x02, // source ID - 0x01, // source pin - 0x00, // iJack -} - -var ClassSpecificMIDIOutJack1 = ClassSpecificType{ - data: classSpecificMIDIOutJack1[:], -} - -var classSpecificMIDIOutJack2 = [classSpecificMIDIOutJackLen]byte{ - classSpecificMIDIOutJackLen, - TypeClassSpecific, - 0x03, // MIDI Out jack - 0x02, // Jack type (external) - 0x04, // Jack ID - 0x01, // number of input pins - 0x01, // source ID - 0x01, // source pin - 0x00, // iJack -} - -var ClassSpecificMIDIOutJack2 = ClassSpecificType{ - data: classSpecificMIDIOutJack2[:], -} - -const classSpecificMIDIEndpointLen = 5 - -var classSpecificMIDIOutEndpoint = [classSpecificMIDIEndpointLen]byte{ - classSpecificMIDIEndpointLen, - TypeClassSpecificEndpoint, - 0x01, // CS endpoint - 0x01, // number MIDI IN jacks - 0x01, // assoc Jack ID -} - -var ClassSpecificMIDIOutEndpoint = ClassSpecificType{ - data: classSpecificMIDIOutEndpoint[:], -} - -var classSpecificMIDIInEndpoint = [classSpecificMIDIEndpointLen]byte{ - classSpecificMIDIEndpointLen, - TypeClassSpecificEndpoint, - 0x01, // CS endpoint - 0x01, // number MIDI Out jacks - 0x03, // assoc Jack ID -} - -var ClassSpecificMIDIInEndpoint = ClassSpecificType{ - data: classSpecificMIDIInEndpoint[:], -} - -const endpointMIDITypeLen = 9 - -var endpointEP6IN = [endpointMIDITypeLen]byte{ - endpointMIDITypeLen, - TypeEndpoint, - 0x86, // EndpointAddress - 0x02, // Attributes - 0x40, // MaxPacketSizeL - 0x00, // MaxPacketSizeH - 0x00, // Interval - 0x00, // refresh - 0x00, // sync address -} - -var EndpointEP6IN = EndpointType{ - data: endpointEP6IN[:], -} - -var endpointEP7OUT = [endpointMIDITypeLen]byte{ - endpointMIDITypeLen, - TypeEndpoint, - 0x07, // EndpointAddress - 0x02, // Attributes - 0x40, // MaxPacketSizeL - 0x00, // MaxPacketSizeH - 0x00, // Interval - 0x00, // refresh - 0x00, // sync address -} - -var EndpointEP7OUT = EndpointType{ - data: endpointEP7OUT[:], -} - -var configurationCDCMIDI = [configurationTypeLen]byte{ - configurationTypeLen, - TypeConfiguration, - 0xaf, 0x00, // adjust length as needed - 0x04, // number of interfaces - 0x01, // configuration value - 0x00, // index to string description - 0xa0, // attributes - 0x32, // maxpower -} - -var ConfigurationCDCMIDI = ConfigurationType{ - data: configurationCDCMIDI[:], -} - -var CDCMIDI = Descriptor{ - Device: DeviceCDC.Bytes(), - Configuration: Append([][]byte{ - ConfigurationCDCMIDI.Bytes(), - InterfaceAssociationCDC.Bytes(), - InterfaceCDCControl.Bytes(), - ClassSpecificCDCHeader.Bytes(), - ClassSpecificCDCACM.Bytes(), - ClassSpecificCDCUnion.Bytes(), - ClassSpecificCDCCallManagement.Bytes(), - EndpointEP1IN.Bytes(), - InterfaceCDCData.Bytes(), - EndpointEP2OUT.Bytes(), - EndpointEP3IN.Bytes(), - InterfaceAssociationMIDI.Bytes(), - InterfaceAudio.Bytes(), - ClassSpecificAudioInterface.Bytes(), - InterfaceMIDIStreaming.Bytes(), - ClassSpecificMIDIHeader.Bytes(), - ClassSpecificMIDIInJack1.Bytes(), - ClassSpecificMIDIInJack2.Bytes(), - ClassSpecificMIDIOutJack1.Bytes(), - ClassSpecificMIDIOutJack2.Bytes(), - EndpointEP7OUT.Bytes(), - ClassSpecificMIDIOutEndpoint.Bytes(), - EndpointEP6IN.Bytes(), - ClassSpecificMIDIInEndpoint.Bytes(), - }), -} diff --git a/emb/machine/_usb/descriptor/msc.go b/emb/machine/_usb/descriptor/msc.go deleted file mode 100644 index 55c6ddd..0000000 --- a/emb/machine/_usb/descriptor/msc.go +++ /dev/null @@ -1,75 +0,0 @@ -package descriptor - -const ( - interfaceClassMSC = 0x08 - mscSubclassSCSI = 0x06 - mscProtocolBOT = 0x50 -) - -var interfaceAssociationMSC = [interfaceAssociationTypeLen]byte{ - interfaceAssociationTypeLen, - TypeInterfaceAssociation, - 0x02, // FirstInterface - 0x01, // InterfaceCount - interfaceClassMSC, // FunctionClass - mscSubclassSCSI, // FunctionSubClass - mscProtocolBOT, // FunctionProtocol - 0x00, // Function -} - -var InterfaceAssociationMSC = InterfaceAssociationType{ - data: interfaceAssociationMSC[:], -} - -var interfaceMSC = [interfaceTypeLen]byte{ - interfaceTypeLen, // Length - TypeInterface, // DescriptorType - 0x02, // InterfaceNumber - 0x00, // AlternateSetting - 0x02, // NumEndpoints - interfaceClassMSC, // InterfaceClass (Mass Storage) - mscSubclassSCSI, // InterfaceSubClass (SCSI Transparent) - mscProtocolBOT, // InterfaceProtocol (Bulk-Only Transport) - 0x00, // Interface -} - -var InterfaceMSC = InterfaceType{ - data: interfaceMSC[:], -} - -var configurationMSC = [configurationTypeLen]byte{ - configurationTypeLen, - TypeConfiguration, - 0x6a, 0x00, // wTotalLength - 0x03, // number of interfaces (bNumInterfaces) - 0x01, // configuration value (bConfigurationValue) - 0x00, // index to string description (iConfiguration) - 0xa0, // attributes (bmAttributes) - 0x32, // maxpower (100 mA) (bMaxPower) -} - -var ConfigurationMSC = ConfigurationType{ - data: configurationMSC[:], -} - -// Mass Storage Class -var MSC = Descriptor{ - Device: DeviceCDC.Bytes(), - Configuration: Append([][]byte{ - ConfigurationMSC.Bytes(), - InterfaceAssociationCDC.Bytes(), - InterfaceCDCControl.Bytes(), - ClassSpecificCDCHeader.Bytes(), - ClassSpecificCDCACM.Bytes(), - ClassSpecificCDCUnion.Bytes(), - ClassSpecificCDCCallManagement.Bytes(), - EndpointEP1IN.Bytes(), - InterfaceCDCData.Bytes(), - EndpointEP2OUT.Bytes(), - EndpointEP3IN.Bytes(), - InterfaceAssociationMSC.Bytes(), - InterfaceMSC.Bytes(), - EndpointMSCIN.Bytes(), - EndpointMSCOUT.Bytes(), - }), -} diff --git a/emb/machine/_usb/doc.go b/emb/machine/_usb/doc.go deleted file mode 100644 index 03dbadc..0000000 --- a/emb/machine/_usb/doc.go +++ /dev/null @@ -1,4 +0,0 @@ -// package usb contains the subpackages with USB descriptors and device -// implementations for standard USB device classes such as the Communcation -// Data Class (CDC), Human Interface Device (HID), and Audio Device Class (ADC). -package usb diff --git a/emb/machine/_usb/hid/buffer.go b/emb/machine/_usb/hid/buffer.go deleted file mode 100644 index 2674bbd..0000000 --- a/emb/machine/_usb/hid/buffer.go +++ /dev/null @@ -1,52 +0,0 @@ -package hid - -import ( - "runtime/volatile" -) - -const bufferSize = 128 - -// RingBuffer is ring buffer implementation inspired by post at -// https://www.embeddedrelated.com/showthread/comp.arch.embedded/77084-1.php -type RingBuffer struct { - rxbuffer [bufferSize][9]byte - head volatile.Register8 - tail volatile.Register8 -} - -// NewRingBuffer returns a new ring buffer. -func NewRingBuffer() *RingBuffer { - return &RingBuffer{} -} - -// Used returns how many bytes in buffer have been used. -func (rb *RingBuffer) Used() uint8 { - return uint8(rb.head.Get() - rb.tail.Get()) -} - -// Put stores a byte in the buffer. If the buffer is already -// full, the method will return false. -func (rb *RingBuffer) Put(val []byte) bool { - if rb.Used() != bufferSize { - rb.head.Set(rb.head.Get() + 1) - copy(rb.rxbuffer[rb.head.Get()%bufferSize][:], val) - return true - } - return false -} - -// Get returns a byte from the buffer. If the buffer is empty, -// the method will return a false as the second value. -func (rb *RingBuffer) Get() ([]byte, bool) { - if rb.Used() != 0 { - rb.tail.Set(rb.tail.Get() + 1) - return rb.rxbuffer[rb.tail.Get()%bufferSize][:], true - } - return nil, false -} - -// Clear resets the head and tail pointer to zero. -func (rb *RingBuffer) Clear() { - rb.head.Set(0) - rb.tail.Set(0) -} diff --git a/emb/machine/_usb/hid/doc.go b/emb/machine/_usb/hid/doc.go deleted file mode 100644 index 82797a5..0000000 --- a/emb/machine/_usb/hid/doc.go +++ /dev/null @@ -1,2 +0,0 @@ -// package hid is for USB Human Interface Devices. -package hid diff --git a/emb/machine/_usb/hid/hid.go b/emb/machine/_usb/hid/hid.go deleted file mode 100644 index 791fd06..0000000 --- a/emb/machine/_usb/hid/hid.go +++ /dev/null @@ -1,100 +0,0 @@ -package hid - -import ( - "errors" - "machine" - "machine/usb" - "machine/usb/descriptor" -) - -// from usb-hid.go -var ( - ErrHIDInvalidPort = errors.New("invalid USB port") - ErrHIDInvalidCore = errors.New("invalid USB core") - ErrHIDReportTransfer = errors.New("failed to transfer HID report") -) - -const ( - hidEndpoint = usb.HID_ENDPOINT_IN - - REPORT_TYPE_INPUT = 1 - REPORT_TYPE_OUTPUT = 2 - REPORT_TYPE_FEATURE = 3 -) - -type hidDevicer interface { - TxHandler() bool - RxHandler([]byte) bool -} - -var devices [5]hidDevicer -var size int - -// SetHandler sets the handler. Only the first time it is called, it -// calls machine.EnableHID for USB configuration -func SetHandler(d hidDevicer) { - if size == 0 { - machine.ConfigureUSBEndpoint(descriptor.CDCHID, - []usb.EndpointConfig{ - { - Index: usb.HID_ENDPOINT_OUT, - IsIn: false, - Type: usb.ENDPOINT_TYPE_INTERRUPT, - RxHandler: rxHandler, - }, - { - Index: usb.HID_ENDPOINT_IN, - IsIn: true, - Type: usb.ENDPOINT_TYPE_INTERRUPT, - TxHandler: txHandler, - }, - }, - []usb.SetupConfig{ - { - Index: usb.HID_INTERFACE, - Handler: setupHandler, - }, - }) - } - - devices[size] = d - size++ -} - -func txHandler() { - for _, d := range devices { - if d == nil { - continue - } - if done := d.TxHandler(); done { - return - } - } -} - -func rxHandler(b []byte) { - for _, d := range devices { - if d == nil { - continue - } - if done := d.RxHandler(b); done { - return - } - } -} - -var DefaultSetupHandler = setupHandler - -func setupHandler(setup usb.Setup) bool { - ok := false - if setup.BmRequestType == usb.SET_REPORT_TYPE && setup.BRequest == usb.SET_IDLE { - machine.SendZlp() - ok = true - } - return ok -} - -// SendUSBPacket sends a HIDPacket. -func SendUSBPacket(b []byte) { - machine.SendUSBInPacket(hidEndpoint, b) -} diff --git a/emb/machine/_usb/hid/joystick/joystick.go b/emb/machine/_usb/hid/joystick/joystick.go deleted file mode 100644 index 2c2f719..0000000 --- a/emb/machine/_usb/hid/joystick/joystick.go +++ /dev/null @@ -1,125 +0,0 @@ -package joystick - -import ( - "machine" - "machine/usb" - "machine/usb/descriptor" - "machine/usb/hid" -) - -var Joystick *joystick - -type joystick struct { - State - buf *hid.RingBuffer - waitTxc bool - rxHandlerFunc func(b []byte) - setupFunc func(setup usb.Setup) bool -} - -func init() { - if Joystick == nil { - Joystick = newDefaultJoystick() - } -} - -// UseSettings overrides the Joystick settings. This function must be -// called from init(). -func UseSettings(def Definitions, rxHandlerFunc func(b []byte), setupFunc func(setup usb.Setup) bool, hidDesc []byte) *joystick { - js := &joystick{ - buf: hid.NewRingBuffer(), - State: def.NewState(), - } - if setupFunc == nil { - setupFunc = hid.DefaultSetupHandler - } - if rxHandlerFunc == nil { - rxHandlerFunc = js.rxHandlerFunc - } - if len(hidDesc) == 0 { - hidDesc = descriptor.JoystickDefaultHIDReport - } - class, err := descriptor.FindClassHIDType(descriptor.CDCJoystick.Configuration, descriptor.ClassHIDJoystick.Bytes()) - if err != nil { - // TODO: some way to notify about error - return nil - } - - class.ClassLength(uint16(len(hidDesc))) - descriptor.CDCJoystick.HID[2] = hidDesc - - machine.ConfigureUSBEndpoint(descriptor.CDCJoystick, - []usb.EndpointConfig{ - { - Index: usb.HID_ENDPOINT_OUT, - IsIn: false, - Type: usb.ENDPOINT_TYPE_INTERRUPT, - RxHandler: rxHandlerFunc, - }, - { - Index: usb.HID_ENDPOINT_IN, - IsIn: true, - Type: usb.ENDPOINT_TYPE_INTERRUPT, - TxHandler: js.handler, - }, - }, - []usb.SetupConfig{ - { - Index: usb.HID_INTERFACE, - Handler: setupFunc, - }, - }, - ) - Joystick = js - return js -} - -func newDefaultJoystick() *joystick { - def := DefaultDefinitions() - js := UseSettings(def, nil, nil, nil) - return js -} - -// Port returns the USB Joystick port. -func Port() *joystick { - return Joystick -} - -func (m *joystick) handler() { - m.waitTxc = false - if b, ok := m.buf.Get(); ok { - m.waitTxc = true - hid.SendUSBPacket(b) - } -} - -func (m *joystick) tx(b []byte) { - if machine.USBDev.InitEndpointComplete { - if m.waitTxc { - m.buf.Put(b) - } else { - m.waitTxc = true - hid.SendUSBPacket(b) - } - } -} - -func (m *joystick) ready() bool { - return true -} - -func (m *joystick) rxHandler(b []byte) { - if m.rxHandlerFunc != nil { - m.rxHandlerFunc(b) - } -} - -// to InterruptOut -func (m *joystick) SendReport(reportID byte, b []byte) { - m.tx(append([]byte{reportID}, b...)) -} - -func (m *joystick) SendState() { - b, _ := m.State.MarshalBinary() - m.tx(b) -} diff --git a/emb/machine/_usb/hid/joystick/state.go b/emb/machine/_usb/hid/joystick/state.go deleted file mode 100644 index 08265ab..0000000 --- a/emb/machine/_usb/hid/joystick/state.go +++ /dev/null @@ -1,174 +0,0 @@ -package joystick - -import ( - "machine/usb/descriptor" - - "encoding/binary" -) - -type HatDirection uint8 - -const ( - HatUp HatDirection = iota - HatRightUp - HatRight - HatRightDown - HatDown - HatLeftDown - HatLeft - HatLeftUp - HatCenter -) - -type Constraint struct { - MinIn int - MaxIn int - MinOut int16 - MaxOut int16 -} - -type AxisValue struct { - constraint Constraint - Value int -} - -func fit(x, in_min, in_max int, out_min, out_max int16) int16 { - return int16((x-in_min)*(int(out_max)-int(out_min))/(in_max-in_min) + int(out_min)) -} - -func fitf(x, in_min, in_max, out_min, out_max float32) float32 { - return x - in_min*(out_max-out_min)/(in_max-in_min) + out_min -} - -func limit(v, max int) int { - if v > max { - v = max - } else if v < -max { - v = -max - } - return v -} - -type Definitions struct { - ReportID byte - ButtonCnt int - HatSwitchCnt int - AxisDefs []Constraint - descriptor []byte -} - -func (c Definitions) Descriptor() []byte { - if len(c.descriptor) > 0 { - return c.descriptor - } - // TODO: build hid descriptor - return nil -} - -func (c Definitions) NewState() State { - bufSize := 1 - hatSwitches := make([]HatDirection, c.HatSwitchCnt) - for i := range hatSwitches { - hatSwitches[i] = HatCenter - } - axises := make([]*AxisValue, 0, len(c.AxisDefs)) - for _, v := range c.AxisDefs { - - axises = append(axises, &AxisValue{ - constraint: v, - Value: 0, - }) - } - btnSize := (c.ButtonCnt + 7) / 8 - bufSize += btnSize - bufSize += (len(hatSwitches) + 1) / 2 - bufSize += len(axises) * 2 - initBuf := make([]byte, bufSize) - initBuf[0] = c.ReportID - return State{ - buf: initBuf, - Buttons: make([]byte, btnSize), - HatSwitches: hatSwitches, - Axises: axises, - } -} - -type State struct { - buf []byte - Buttons []byte - HatSwitches []HatDirection - Axises []*AxisValue -} - -func (s State) MarshalBinary() ([]byte, error) { - s.buf = s.buf[0:1] - s.buf = append(s.buf, s.Buttons...) - if len(s.HatSwitches) > 0 { - hat := byte(0) - for i, v := range s.HatSwitches { - if i != 0 && i%2 == 0 { - s.buf = append(s.buf, hat) - hat = 0 - } - hat <<= 4 - hat |= byte(v & 0xf) - } - s.buf = append(s.buf, hat) - } - for _, v := range s.Axises { - c := v.constraint - val := fit(v.Value, c.MinIn, c.MaxIn, c.MinOut, c.MaxOut) - s.buf = binary.LittleEndian.AppendUint16(s.buf, uint16(val)) - } - return s.buf, nil -} - -func (s State) Button(index int) bool { - idx := index / 8 - bit := uint8(1 << (index % 8)) - return s.Buttons[idx]&bit > 0 -} - -func (s State) SetButton(index int, push bool) { - idx := index / 8 - bit := uint8(1 << (index % 8)) - b := s.Buttons[idx] - b &= ^bit - if push { - b |= bit - } - s.Buttons[idx] = b -} - -func (s State) Hat(index int) HatDirection { - return s.HatSwitches[index] -} - -func (s State) SetHat(index int, dir HatDirection) { - s.HatSwitches[index] = dir -} - -func (s State) Axis(index int) int { - return s.Axises[index].Value -} - -func (s State) SetAxis(index int, v int) { - s.Axises[index].Value = v -} - -func DefaultDefinitions() Definitions { - return Definitions{ - ReportID: 1, - ButtonCnt: 16, - HatSwitchCnt: 1, - AxisDefs: []Constraint{ - {MinIn: -32767, MaxIn: 32767, MinOut: -32767, MaxOut: 32767}, - {MinIn: -32767, MaxIn: 32767, MinOut: -32767, MaxOut: 32767}, - {MinIn: -32767, MaxIn: 32767, MinOut: -32767, MaxOut: 32767}, - {MinIn: -32767, MaxIn: 32767, MinOut: -32767, MaxOut: 32767}, - {MinIn: -32767, MaxIn: 32767, MinOut: -32767, MaxOut: 32767}, - {MinIn: -32767, MaxIn: 32767, MinOut: -32767, MaxOut: 32767}, - }, - descriptor: descriptor.JoystickDefaultHIDReport, - } -} diff --git a/emb/machine/_usb/hid/keyboard/keyboard.go b/emb/machine/_usb/hid/keyboard/keyboard.go deleted file mode 100644 index 9f5f420..0000000 --- a/emb/machine/_usb/hid/keyboard/keyboard.go +++ /dev/null @@ -1,525 +0,0 @@ -package keyboard - -import ( - "errors" - "machine" - "machine/usb/hid" -) - -// from usb-hid-keyboard.go -var ( - ErrInvalidCodepoint = errors.New("invalid Unicode codepoint") - ErrInvalidKeycode = errors.New("invalid keyboard keycode") - ErrInvalidUTF8 = errors.New("invalid UTF-8 encoding") - ErrKeypressMaximum = errors.New("maximum keypresses exceeded") -) - -var Keyboard *keyboard - -// Keyboard represents a USB HID keyboard device with support for international -// layouts and various control, system, multimedia, and consumer keycodes. -// -// Keyboard implements the io.Writer interface that translates UTF-8 encoded -// byte strings into sequences of keypress events. -type keyboard struct { - // led holds the current state of all keyboard LEDs: - // 1=NumLock 2=CapsLock 4=ScrollLock 8=Compose 16=Kana - led uint8 - - // mod holds the current state of all keyboard modifier keys: - // 1=LeftCtrl 2=LeftShift 4=LeftAlt 8=LeftGUI - // 16=RightCtrl 32=RightShift 64=RightAlt 128=RightGUI - mod uint8 - - // key holds a list of all keyboard keys currently pressed. - key [hidKeyboardKeyCount]uint8 - con [hidKeyboardConCount]uint16 - sys [hidKeyboardSysCount]uint8 - - // decode holds the current state of the UTF-8 decoder. - decode decodeState - - // wideChar holds high bits for the UTF-8 decoder. - wideChar uint16 - - buf *hid.RingBuffer - waitTxc bool -} - -// decodeState represents a state in the UTF-8 decode state machine. -type decodeState uint8 - -// Constant enumerated values of type decodeState. -const ( - decodeReset decodeState = iota - decodeByte1 - decodeByte2 - decodeByte3 -) - -func init() { - if Keyboard == nil { - Keyboard = newKeyboard() - hid.SetHandler(Keyboard) - } -} - -// New returns the USB hid-keyboard port. -// Deprecated, better to just use Port() -func New() *keyboard { - return Port() -} - -// Port returns the USB hid-keyboard port. -func Port() *keyboard { - return Keyboard -} - -func newKeyboard() *keyboard { - return &keyboard{ - buf: hid.NewRingBuffer(), - } -} - -func (kb *keyboard) TxHandler() bool { - kb.waitTxc = false - if b, ok := kb.buf.Get(); ok { - kb.waitTxc = true - hid.SendUSBPacket(b) - return true - } - return false -} - -func (kb *keyboard) RxHandler(b []byte) bool { - if len(b) >= 2 && b[0] == 2 /* ReportID */ { - kb.led = b[1] - } - return false -} - -func (kb *keyboard) tx(b []byte) { - if machine.USBDev.InitEndpointComplete { - if kb.waitTxc { - kb.buf.Put(b) - } else { - kb.waitTxc = true - hid.SendUSBPacket(b) - } - } -} - -func (kb *keyboard) NumLockLed() bool { - return kb.led&1 != 0 -} - -func (kb *keyboard) CapsLockLed() bool { - return kb.led&2 != 0 -} - -func (kb *keyboard) ScrollLockLed() bool { - return kb.led&4 != 0 -} - -func (kb *keyboard) ready() bool { - return true -} - -// Write transmits press-and-release key sequences for each Keycode translated -// from the given UTF-8 byte string. Write implements the io.Writer interface -// and conforms to all documented conventions for arguments and return values. -func (kb *keyboard) Write(b []byte) (n int, err error) { - for _, c := range b { - if err = kb.WriteByte(c); nil != err { - break - } - n += 1 - } - return -} - -// WriteByte processes a single byte from a UTF-8 byte string. This method is a -// stateful method with respect to the receiver Keyboard, meaning that its exact -// behavior will depend on the current state of its UTF-8 decode state machine: -// -// 1. If the given byte is a valid ASCII encoding (0-127), then a keypress -// sequence is immediately transmitted for the respective Keycode. -// 2. If the given byte represents the final byte in a multi-byte codepoint, -// then a keypress sequence is immediately transmitted by translating the -// multi-byte codepoint to its respective Keycode. -// 3. If the given byte appears to represent high bits for a multi-byte -// codepoint, then the bits are copied to the receiver's internal state -// machine buffer for use by a subsequent call to WriteByte() (or Write()) -// that completes the codepoint. -// 4. If the given byte is out of range, or contains illegal bits for the -// current state of the UTF-8 decoder, then the UTF-8 decode state machine -// is reset to its initial state. -// -// In cases 3 and 4, a keypress sequence is not generated and no data is -// transmitted. In case 3, additional bytes must be received via WriteByte() -// (or Write()) to complete or discard the current codepoint. -func (kb *keyboard) WriteByte(b byte) error { - switch { - case b < 0x80: - // 1-byte encoding (0x00-0x7F) - kb.decode = decodeByte1 - return kb.write(uint16(b)) - - case b < 0xC0: - // 2nd, 3rd, or 4th byte (0x80-0xBF) - b = Keycode(b).key() - switch kb.decode { - case decodeByte2: - kb.decode = decodeByte1 - return kb.write(kb.wideChar | uint16(b)) - case decodeByte3: - kb.decode = decodeByte2 - kb.wideChar |= uint16(b) << 6 - } - - case b < 0xE0: - // 2-byte encoding (0xC2-0xDF), or illegal byte 2 (0xC0-0xC1) - kb.decode = decodeByte2 - kb.wideChar = uint16(b&0x1F) << 6 - - case b < 0xF0: - // 3-byte encoding (0xE0-0xEF) - kb.decode = decodeByte3 - kb.wideChar = uint16(b&0x0F) << 12 - - default: - // 4-byte encoding unsupported (0xF0-0xF4), or illegal byte 4 (0xF5-0xFF) - kb.decode = decodeReset - return ErrInvalidUTF8 - } - return nil -} - -func (kb *keyboard) write(p uint16) error { - c := keycode(p) - if 0 == c { - return ErrInvalidCodepoint - } - if d := deadkey(c); 0 != d { - if err := kb.writeKeycode(d); nil != err { - return err - } - } - return kb.writeKeycode(c) -} - -func (kb *keyboard) writeKeycode(c Keycode) error { - var b [9]byte - b[0] = 0x02 - b[1] = c.mod() - b[2] = 0 - b[3] = c.key() - b[4] = 0 - b[5] = 0 - b[6] = 0 - b[7] = 0 - b[8] = 0 - if !kb.sendKey(false, b[:]) { - return hid.ErrHIDReportTransfer - } - - b[1] = 0 - b[3] = 0 - if !kb.sendKey(false, b[:]) { - return hid.ErrHIDReportTransfer - } - return nil -} - -// Press transmits a press-and-release sequence for the given Keycode, which -// simulates a discrete keypress event. -// -// The following values of Keycode are supported: -// -// 0x0020 - 0x007F ASCII (U+0020 to U+007F) [USES LAYOUT] -// 0x0080 - 0xC1FF Unicode (U+0080 to U+C1FF) [USES LAYOUT] -// 0xC200 - 0xDFFF UTF-8 packed (U+0080 to U+07FF) [USES LAYOUT] -// 0xE000 - 0xE0FF Modifier key (bitmap, 8 keys, Shift/Ctrl/Alt/GUI) -// 0xE200 - 0xE2FF System key (HID usage code, page 1) -// 0xE400 - 0xE7FF Media/Consumer key (HID usage code, page 12) -// 0xF000 - 0xFFFF Normal key (HID usage code, page 7) -func (kb *keyboard) Press(c Keycode) error { - if err := kb.Down(c); nil != err { - return err - } - return kb.Up(c) -} - -func (kb *keyboard) sendKey(consumer bool, b []byte) bool { - kb.tx(b) - return true -} - -func (kb *keyboard) keyboardSendKeys(consumer bool) bool { - var b [9]byte - - if !consumer { - b[0] = 0x02 // REPORT_ID - b[1] = kb.mod - b[2] = 0x02 - b[3] = kb.key[0] - b[4] = kb.key[1] - b[5] = kb.key[2] - b[6] = kb.key[3] - b[7] = kb.key[4] - b[8] = kb.key[5] - return kb.sendKey(consumer, b[:]) - - } else { - b[0] = 0x03 // REPORT_ID - b[1] = uint8(kb.con[0]) - b[2] = uint8((kb.con[0] & 0x0300) >> 8) - - return kb.sendKey(consumer, b[:3]) - } -} - -// Down transmits a key-down event for the given Keycode. -// -// The host will interpret the key as being held down continuously until a -// corresponding key-up event is transmitted, e.g., via method Up(). -// -// See godoc comment on method Press() for details on what input is accepted and -// how it is interpreted. -func (kb *keyboard) Down(c Keycode) error { - var res uint8 - msb := c >> 8 - if msb >= 0xC2 { - if msb < 0xE0 { - c = ((msb & 0x1F) << 6) | Keycode(c.key()) - } else { - switch msb { - case 0xF0: - return kb.down(uint8(c), 0) - - case 0xE0: - return kb.down(0, uint8(c)) - - case 0xE2: - return kb.downSys(uint8(c)) - - default: - if 0xE4 <= msb && msb <= 0xE7 { - return kb.downCon(uint16(c & 0x03FF)) - } - return ErrInvalidKeycode - } - } - } - c = keycode(uint16(c)) - if 0 == c { - return ErrInvalidCodepoint - } - if d := deadkey(c); 0 != d { - res = kb.mod - if 0 != res { - kb.mod = 0 - kb.keyboardSendKeys(false) - } - kb.down(d.key(), d.mod()) - kb.up(d.key(), d.mod()) - } - return kb.down(c.key(), c.mod()|res) -} - -func (kb *keyboard) down(key uint8, mod uint8) error { - send := false - if 0 != mod { - if kb.mod&mod != mod { - kb.mod |= mod - send = true - } - } - if 0 != key { - for _, k := range kb.key { - if k == key { - goto end - } - } - for i, k := range kb.key { - if 0 == k { - kb.key[i] = key - send = true - goto end - } - } - return ErrKeypressMaximum - } -end: - if send { - if !kb.keyboardSendKeys(false) { - return hid.ErrHIDReportTransfer - } - } - return nil -} - -func (kb *keyboard) downCon(key uint16) error { - if 0 == key { - return ErrInvalidKeycode - } - for _, k := range kb.con { - if key == k { - return nil // already pressed - } - } - for i, k := range kb.con { - if 0 == k { - kb.con[i] = key - if !kb.keyboardSendKeys(true) { - return hid.ErrHIDReportTransfer - } - return nil - } - } - return ErrKeypressMaximum -} - -func (kb *keyboard) downSys(key uint8) error { - if 0 == key { - return ErrInvalidKeycode - } - for _, k := range kb.sys { - if key == k { - return nil // already pressed - } - } - for i, k := range kb.sys { - if 0 == k { - kb.sys[i] = key - if !kb.keyboardSendKeys(true) { - return hid.ErrHIDReportTransfer - } - return nil - } - } - return ErrKeypressMaximum -} - -// Up transmits a key-up event for the given Keycode. -// -// See godoc comment on method Press() for details on what input is accepted and -// how it is interpreted. -func (kb *keyboard) Up(c Keycode) error { - msb := c >> 8 - if msb >= 0xC2 { - if msb < 0xE0 { - c = ((msb & 0x1F) << 6) | Keycode(c.key()) - } else { - switch msb { - case 0xF0: - return kb.up(uint8(c), 0) - - case 0xE0: - return kb.up(0, uint8(c)) - - case 0xE2: - return kb.upSys(uint8(c)) - - default: - if 0xE4 <= msb && msb <= 0xE7 { - return kb.upCon(uint16(c & 0x03FF)) - } - return ErrInvalidKeycode - } - } - } - c = keycode(uint16(c)) - if 0 == c { - return ErrInvalidCodepoint - } - return kb.up(c.key(), c.mod()) -} - -// Release transmits a key-up event for all keyboard keys currently pressed as -// if the user removed his/her hands from the keyboard entirely. -func (kb *keyboard) Release() error { - - bits := uint16(kb.mod) - kb.mod = 0 - for i, k := range kb.key { - bits |= uint16(k) - kb.key[i] = 0 - } - if 0 != bits { - if !kb.keyboardSendKeys(false) { - return hid.ErrHIDReportTransfer - } - } - bits = 0 - for i, k := range kb.con { - bits |= k - kb.con[i] = 0 - } - for i, k := range kb.sys { - bits |= uint16(k) - kb.sys[i] = 0 - } - if 0 != bits { - if !kb.keyboardSendKeys(true) { - return hid.ErrHIDReportTransfer - } - } - return nil -} - -func (kb *keyboard) up(key uint8, mod uint8) error { - send := false - if 0 != mod { - if kb.mod&mod != 0 { - kb.mod &^= mod - send = true - } - } - if 0 != key { - for i, k := range kb.key { - if key == k { - kb.key[i] = 0 - send = true - } - } - } - if send { - if !kb.keyboardSendKeys(false) { - return hid.ErrHIDReportTransfer - } - } - return nil -} - -func (kb *keyboard) upCon(key uint16) error { - if 0 == key { - return ErrInvalidKeycode - } - for i, k := range kb.con { - if key == k { - kb.con[i] = 0 - if !kb.keyboardSendKeys(true) { - return hid.ErrHIDReportTransfer - } - return nil - } - } - return nil -} - -func (kb *keyboard) upSys(key uint8) error { - if 0 == key { - return ErrInvalidKeycode - } - for i, k := range kb.sys { - if key == k { - kb.sys[i] = 0 - if !kb.keyboardSendKeys(true) { - return hid.ErrHIDReportTransfer - } - return nil - } - } - return nil -} diff --git a/emb/machine/_usb/hid/keyboard/keycode.go b/emb/machine/_usb/hid/keyboard/keycode.go deleted file mode 100644 index 762f65b..0000000 --- a/emb/machine/_usb/hid/keyboard/keycode.go +++ /dev/null @@ -1,534 +0,0 @@ -package keyboard - -// Keycode is a package-defined bitmap used to encode the value of a given key. -type Keycode uint16 - -// keycode returns the given Unicode codepoint translated to a Keycode sequence. -// Unicode codepoints greater than U+FFFF are unsupported. -// -//go:inline -func keycode(p uint16) Keycode { - if p < 0x80 { - return ascii[p] - } else if p >= 0xA0 && p < 0x0100 { - return iso88591[p-0xA0] - } else if uint16(UNICODE20AC) == p { - return UNICODE20AC.mask() - } - return 0 -} - -//go:inline -func deadkey(c Keycode) Keycode { - switch c & deadkeysMask { - case acuteAccentBits: - return deadkeyAcuteAccent - case circumflexBits: - return deadkeyCircumflex - case diaeresisBits: - return deadkeyDiaeresis - case graveAccentBits: - return deadkeyGraveAccent - case tildeBits: - return deadkeyTilde - } - return 0 -} - -//go:inline -func (c Keycode) mask() Keycode { return c & keycodeMask } - -//go:inline -func (c Keycode) key() uint8 { return uint8(c & keyMask) } - -//go:inline -func (c Keycode) mod() uint8 { - var m Keycode - if 0 != c&shiftMask { - m |= KeyModifierShift - } - if 0 != c&altgrMask { - m |= KeyModifierRightAlt - } - return uint8(m) -} - -//go:inline -func (c Keycode) Shift() Keycode { return c | KeyModifierShift } - -const ( - hidKeyboardKeyCount = 6 // Max number of simultaneous keypresses - hidKeyboardSysCount = 3 - hidKeyboardConCount = 4 -) - -// Keycodes common to all Keyboard layouts -const ( - KeyModifierCtrl Keycode = 0x01 | 0xE000 - KeyModifierShift Keycode = 0x02 | 0xE000 - KeyModifierAlt Keycode = 0x04 | 0xE000 - KeyModifierGUI Keycode = 0x08 | 0xE000 - KeyModifierLeftCtrl Keycode = 0x01 | 0xE000 - KeyModifierLeftShift Keycode = 0x02 | 0xE000 - KeyModifierLeftAlt Keycode = 0x04 | 0xE000 - KeyModifierLeftGUI Keycode = 0x08 | 0xE000 - KeyModifierRightCtrl Keycode = 0x10 | 0xE000 - KeyModifierRightShift Keycode = 0x20 | 0xE000 - KeyModifierRightAlt Keycode = 0x40 | 0xE000 - KeyModifierRightGUI Keycode = 0x80 | 0xE000 - - // KeySystemXXX is not supported now - KeySystemPowerDown Keycode = 0x81 | 0xE200 - KeySystemSleep Keycode = 0x82 | 0xE200 - KeySystemWakeUp Keycode = 0x83 | 0xE200 - - KeyMediaPlay Keycode = 0xB0 | 0xE400 - KeyMediaPause Keycode = 0xB1 | 0xE400 - KeyMediaRecord Keycode = 0xB2 | 0xE400 - KeyMediaFastForward Keycode = 0xB3 | 0xE400 - KeyMediaRewind Keycode = 0xB4 | 0xE400 - KeyMediaNextTrack Keycode = 0xB5 | 0xE400 - KeyMediaPrevTrack Keycode = 0xB6 | 0xE400 - KeyMediaStop Keycode = 0xB7 | 0xE400 - KeyMediaEject Keycode = 0xB8 | 0xE400 - KeyMediaRandomPlay Keycode = 0xB9 | 0xE400 - KeyMediaPlayPause Keycode = 0xCD | 0xE400 - KeyMediaPlaySkip Keycode = 0xCE | 0xE400 - KeyMediaMute Keycode = 0xE2 | 0xE400 - KeyMediaVolumeInc Keycode = 0xE9 | 0xE400 - KeyMediaVolumeDec Keycode = 0xEA | 0xE400 - - KeyA Keycode = 4 | 0xF000 - KeyB Keycode = 5 | 0xF000 - KeyC Keycode = 6 | 0xF000 - KeyD Keycode = 7 | 0xF000 - KeyE Keycode = 8 | 0xF000 - KeyF Keycode = 9 | 0xF000 - KeyG Keycode = 10 | 0xF000 - KeyH Keycode = 11 | 0xF000 - KeyI Keycode = 12 | 0xF000 - KeyJ Keycode = 13 | 0xF000 - KeyK Keycode = 14 | 0xF000 - KeyL Keycode = 15 | 0xF000 - KeyM Keycode = 16 | 0xF000 - KeyN Keycode = 17 | 0xF000 - KeyO Keycode = 18 | 0xF000 - KeyP Keycode = 19 | 0xF000 - KeyQ Keycode = 20 | 0xF000 - KeyR Keycode = 21 | 0xF000 - KeyS Keycode = 22 | 0xF000 - KeyT Keycode = 23 | 0xF000 - KeyU Keycode = 24 | 0xF000 - KeyV Keycode = 25 | 0xF000 - KeyW Keycode = 26 | 0xF000 - KeyX Keycode = 27 | 0xF000 - KeyY Keycode = 28 | 0xF000 - KeyZ Keycode = 29 | 0xF000 - Key1 Keycode = 30 | 0xF000 - Key2 Keycode = 31 | 0xF000 - Key3 Keycode = 32 | 0xF000 - Key4 Keycode = 33 | 0xF000 - Key5 Keycode = 34 | 0xF000 - Key6 Keycode = 35 | 0xF000 - Key7 Keycode = 36 | 0xF000 - Key8 Keycode = 37 | 0xF000 - Key9 Keycode = 38 | 0xF000 - Key0 Keycode = 39 | 0xF000 - KeyEnter Keycode = 40 | 0xF000 - KeyEsc Keycode = 41 | 0xF000 - KeyBackspace Keycode = 42 | 0xF000 - KeyTab Keycode = 43 | 0xF000 - KeySpace Keycode = 44 | 0xF000 - KeyMinus Keycode = 45 | 0xF000 - KeyEqual Keycode = 46 | 0xF000 - KeyLeftBrace Keycode = 47 | 0xF000 - KeyRightBrace Keycode = 48 | 0xF000 - KeyBackslash Keycode = 49 | 0xF000 - KeyNonUsNum Keycode = 50 | 0xF000 - KeySemicolon Keycode = 51 | 0xF000 - KeyQuote Keycode = 52 | 0xF000 - KeyTilde Keycode = 53 | 0xF000 - KeyComma Keycode = 54 | 0xF000 - KeyPeriod Keycode = 55 | 0xF000 - KeySlash Keycode = 56 | 0xF000 - KeyCapsLock Keycode = 57 | 0xF000 - KeyF1 Keycode = 58 | 0xF000 - KeyF2 Keycode = 59 | 0xF000 - KeyF3 Keycode = 60 | 0xF000 - KeyF4 Keycode = 61 | 0xF000 - KeyF5 Keycode = 62 | 0xF000 - KeyF6 Keycode = 63 | 0xF000 - KeyF7 Keycode = 64 | 0xF000 - KeyF8 Keycode = 65 | 0xF000 - KeyF9 Keycode = 66 | 0xF000 - KeyF10 Keycode = 67 | 0xF000 - KeyF11 Keycode = 68 | 0xF000 - KeyF12 Keycode = 69 | 0xF000 - KeyPrintscreen Keycode = 70 | 0xF000 - KeyScrollLock Keycode = 71 | 0xF000 - KeyPause Keycode = 72 | 0xF000 - KeyInsert Keycode = 73 | 0xF000 - KeyHome Keycode = 74 | 0xF000 - KeyPageUp Keycode = 75 | 0xF000 - KeyDelete Keycode = 76 | 0xF000 - KeyEnd Keycode = 77 | 0xF000 - KeyPageDown Keycode = 78 | 0xF000 - KeyRight Keycode = 79 | 0xF000 - KeyLeft Keycode = 80 | 0xF000 - KeyDown Keycode = 81 | 0xF000 - KeyUp Keycode = 82 | 0xF000 - KeyNumLock Keycode = 83 | 0xF000 - KeypadSlash Keycode = 84 | 0xF000 - KeypadAsterisk Keycode = 85 | 0xF000 - KeypadMinus Keycode = 86 | 0xF000 - KeypadPlus Keycode = 87 | 0xF000 - KeypadEnter Keycode = 88 | 0xF000 - Keypad1 Keycode = 89 | 0xF000 - Keypad2 Keycode = 90 | 0xF000 - Keypad3 Keycode = 91 | 0xF000 - Keypad4 Keycode = 92 | 0xF000 - Keypad5 Keycode = 93 | 0xF000 - Keypad6 Keycode = 94 | 0xF000 - Keypad7 Keycode = 95 | 0xF000 - Keypad8 Keycode = 96 | 0xF000 - Keypad9 Keycode = 97 | 0xF000 - Keypad0 Keycode = 98 | 0xF000 - KeypadPeriod Keycode = 99 | 0xF000 - KeyNonUSBS Keycode = 100 | 0xF000 - KeyMenu Keycode = 101 | 0xF000 - KeyF13 Keycode = 104 | 0xF000 - KeyF14 Keycode = 105 | 0xF000 - KeyF15 Keycode = 106 | 0xF000 - KeyF16 Keycode = 107 | 0xF000 - KeyF17 Keycode = 108 | 0xF000 - KeyF18 Keycode = 109 | 0xF000 - KeyF19 Keycode = 110 | 0xF000 - KeyF20 Keycode = 111 | 0xF000 - KeyF21 Keycode = 112 | 0xF000 - KeyF22 Keycode = 113 | 0xF000 - KeyF23 Keycode = 114 | 0xF000 - KeyF24 Keycode = 115 | 0xF000 - - KeyUpArrow Keycode = KeyUp - KeyDownArrow Keycode = KeyDown - KeyLeftArrow Keycode = KeyLeft - KeyRightArrow Keycode = KeyRight - KeyReturn Keycode = KeyEnter - KeyLeftCtrl Keycode = KeyModifierLeftCtrl - KeyLeftShift Keycode = KeyModifierLeftShift - KeyLeftAlt Keycode = KeyModifierLeftAlt - KeyLeftGUI Keycode = KeyModifierLeftGUI - KeyRightCtrl Keycode = KeyModifierRightCtrl - KeyRightShift Keycode = KeyModifierRightShift - KeyRightAlt Keycode = KeyModifierRightAlt - KeyRightGUI Keycode = KeyModifierRightGUI -) - -// Keycodes for layout US English (0x0904) -const ( - keycodeMask Keycode = 0x07FF - keyMask Keycode = 0x003F - - shiftMask Keycode = 0x0040 - altgrMask Keycode = 0x0080 - deadkeysMask Keycode = 0x0700 - circumflexBits Keycode = 0x0100 - acuteAccentBits Keycode = 0x0200 - graveAccentBits Keycode = 0x0300 - tildeBits Keycode = 0x0400 - diaeresisBits Keycode = 0x0500 - deadkeyCircumflex Keycode = Key6 | shiftMask - deadkeyAcuteAccent Keycode = KeyQuote - deadkeyGraveAccent Keycode = KeyTilde - deadkeyTilde Keycode = KeyTilde | shiftMask - deadkeyDiaeresis Keycode = KeyQuote | shiftMask - - ASCII00 Keycode = 0 // 0 NUL - ASCII01 Keycode = 0 // 1 SOH - ASCII02 Keycode = 0 // 2 STX - ASCII03 Keycode = 0 // 3 ETX - ASCII04 Keycode = 0 // 4 EOT - ASCII05 Keycode = 0 // 5 ENQ - ASCII06 Keycode = 0 // 6 ACK - ASCII07 Keycode = 0 // 7 BEL - ASCII08 Keycode = KeyBackspace // 8 BS - ASCII09 Keycode = KeyTab // 9 TAB - ASCII0A Keycode = KeyEnter // 10 LF - ASCII0B Keycode = 0 // 11 VT - ASCII0C Keycode = 0 // 12 FF - ASCII0D Keycode = 0 // 13 CR - ASCII0E Keycode = 0 // 14 SO - ASCII0F Keycode = 0 // 15 SI - ASCII10 Keycode = 0 // 16 DEL - ASCII11 Keycode = 0 // 17 DC1 - ASCII12 Keycode = 0 // 18 DC2 - ASCII13 Keycode = 0 // 19 DC3 - ASCII14 Keycode = 0 // 20 DC4 - ASCII15 Keycode = 0 // 21 NAK - ASCII16 Keycode = 0 // 22 SYN - ASCII17 Keycode = 0 // 23 ETB - ASCII18 Keycode = 0 // 24 CAN - ASCII19 Keycode = 0 // 25 EM - ASCII1A Keycode = 0 // 26 SUB - ASCII1B Keycode = 0 // 27 ESC - ASCII1C Keycode = 0 // 28 FS - ASCII1D Keycode = 0 // 29 GS - ASCII1E Keycode = 0 // 30 RS - ASCII1F Keycode = 0 // 31 US - - ASCII20 Keycode = KeySpace // 32 SPACE - ASCII21 Keycode = Key1 | shiftMask // 33 ! - ASCII22 Keycode = diaeresisBits | KeySpace // 34 " - ASCII23 Keycode = Key3 | shiftMask // 35 # - ASCII24 Keycode = Key4 | shiftMask // 36 $ - ASCII25 Keycode = Key5 | shiftMask // 37 % - ASCII26 Keycode = Key7 | shiftMask // 38 & - ASCII27 Keycode = acuteAccentBits | KeySpace // 39 ' - ASCII28 Keycode = Key9 | shiftMask // 40 ( - ASCII29 Keycode = Key0 | shiftMask // 41 ) - ASCII2A Keycode = Key8 | shiftMask // 42 * - ASCII2B Keycode = KeyEqual | shiftMask // 43 + - ASCII2C Keycode = KeyComma // 44 , - ASCII2D Keycode = KeyMinus // 45 - - ASCII2E Keycode = KeyPeriod // 46 . - ASCII2F Keycode = KeySlash // 47 / - ASCII30 Keycode = Key0 // 48 0 - ASCII31 Keycode = Key1 // 49 1 - ASCII32 Keycode = Key2 // 50 2 - ASCII33 Keycode = Key3 // 51 3 - ASCII34 Keycode = Key4 // 52 4 - ASCII35 Keycode = Key5 // 53 5 - ASCII36 Keycode = Key6 // 54 6 - ASCII37 Keycode = Key7 // 55 7 - ASCII38 Keycode = Key8 // 55 8 - ASCII39 Keycode = Key9 // 57 9 - ASCII3A Keycode = KeySemicolon | shiftMask // 58 : - ASCII3B Keycode = KeySemicolon // 59 ; - ASCII3C Keycode = KeyComma | shiftMask // 60 < - ASCII3D Keycode = KeyEqual // 61 = - ASCII3E Keycode = KeyPeriod | shiftMask // 62 > - ASCII3F Keycode = KeySlash | shiftMask // 63 ? - ASCII40 Keycode = Key2 | shiftMask // 64 @ - ASCII41 Keycode = KeyA | shiftMask // 65 A - ASCII42 Keycode = KeyB | shiftMask // 66 B - ASCII43 Keycode = KeyC | shiftMask // 67 C - ASCII44 Keycode = KeyD | shiftMask // 68 D - ASCII45 Keycode = KeyE | shiftMask // 69 E - ASCII46 Keycode = KeyF | shiftMask // 70 F - ASCII47 Keycode = KeyG | shiftMask // 71 G - ASCII48 Keycode = KeyH | shiftMask // 72 H - ASCII49 Keycode = KeyI | shiftMask // 73 I - ASCII4A Keycode = KeyJ | shiftMask // 74 J - ASCII4B Keycode = KeyK | shiftMask // 75 K - ASCII4C Keycode = KeyL | shiftMask // 76 L - ASCII4D Keycode = KeyM | shiftMask // 77 M - ASCII4E Keycode = KeyN | shiftMask // 78 N - ASCII4F Keycode = KeyO | shiftMask // 79 O - ASCII50 Keycode = KeyP | shiftMask // 80 P - ASCII51 Keycode = KeyQ | shiftMask // 81 Q - ASCII52 Keycode = KeyR | shiftMask // 82 R - ASCII53 Keycode = KeyS | shiftMask // 83 S - ASCII54 Keycode = KeyT | shiftMask // 84 T - ASCII55 Keycode = KeyU | shiftMask // 85 U - ASCII56 Keycode = KeyV | shiftMask // 86 V - ASCII57 Keycode = KeyW | shiftMask // 87 W - ASCII58 Keycode = KeyX | shiftMask // 88 X - ASCII59 Keycode = KeyY | shiftMask // 89 Y - ASCII5A Keycode = KeyZ | shiftMask // 90 Z - ASCII5B Keycode = KeyLeftBrace // 91 [ - ASCII5C Keycode = KeyBackslash // 92 \ - ASCII5D Keycode = KeyRightBrace // 93 ] - ASCII5E Keycode = circumflexBits | KeySpace // 94 ^ - ASCII5F Keycode = KeyMinus | shiftMask // 95 - ASCII60 Keycode = graveAccentBits | KeySpace // 96 ` - ASCII61 Keycode = KeyA // 97 a - ASCII62 Keycode = KeyB // 98 b - ASCII63 Keycode = KeyC // 99 c - ASCII64 Keycode = KeyD // 100 d - ASCII65 Keycode = KeyE // 101 e - ASCII66 Keycode = KeyF // 102 f - ASCII67 Keycode = KeyG // 103 g - ASCII68 Keycode = KeyH // 104 h - ASCII69 Keycode = KeyI // 105 i - ASCII6A Keycode = KeyJ // 106 j - ASCII6B Keycode = KeyK // 107 k - ASCII6C Keycode = KeyL // 108 l - ASCII6D Keycode = KeyM // 109 m - ASCII6E Keycode = KeyN // 110 n - ASCII6F Keycode = KeyO // 111 o - ASCII70 Keycode = KeyP // 112 p - ASCII71 Keycode = KeyQ // 113 q - ASCII72 Keycode = KeyR // 114 r - ASCII73 Keycode = KeyS // 115 s - ASCII74 Keycode = KeyT // 116 t - ASCII75 Keycode = KeyU // 117 u - ASCII76 Keycode = KeyV // 118 v - ASCII77 Keycode = KeyW // 119 w - ASCII78 Keycode = KeyX // 120 x - ASCII79 Keycode = KeyY // 121 y - ASCII7A Keycode = KeyZ // 122 z - ASCII7B Keycode = KeyLeftBrace | shiftMask // 123 { - ASCII7C Keycode = KeyBackslash | shiftMask // 124 | - ASCII7D Keycode = KeyRightBrace | shiftMask // 125 } - ASCII7E Keycode = tildeBits | KeySpace // 126 ~ - ASCII7F Keycode = KeyBackspace // 127 DEL - ISO88591A0 Keycode = KeySpace // 160 Nonbreakng Space - ISO88591A1 Keycode = Key1 | altgrMask // 161 ¡ Inverted Exclamation - ISO88591A2 Keycode = KeyC | altgrMask | shiftMask // 162 ¢ Cent SIGN - ISO88591A3 Keycode = Key4 | altgrMask | shiftMask // 163 £ Pound Sign - ISO88591A4 Keycode = Key4 | altgrMask // 164 ¤ Currency or Euro Sign - ISO88591A5 Keycode = KeyMinus | altgrMask // 165 ¥ YEN SIGN - ISO88591A6 Keycode = KeyBackslash | altgrMask | shiftMask // 166 ¦ BROKEN BAR ?? - ISO88591A7 Keycode = KeyS | altgrMask | shiftMask // 167 § SECTION SIGN - ISO88591A8 Keycode = KeyQuote | altgrMask | shiftMask // 168 ¨ DIAERESIS - ISO88591A9 Keycode = KeyC | altgrMask // 169 © COPYRIGHT SIGN - ISO88591AA Keycode = 0 // 170 ª FEMININE ORDINAL - ISO88591AB Keycode = KeyLeftBrace | altgrMask // 171 « LEFT DOUBLE ANGLE QUOTE - ISO88591AC Keycode = KeyBackslash | altgrMask // 172 ¬ NOT SIGN ?? - ISO88591AD Keycode = 0 // 173 SOFT HYPHEN - ISO88591AE Keycode = KeyR | altgrMask // 174 ® REGISTERED SIGN - ISO88591AF Keycode = 0 // 175 ¯ MACRON - ISO88591B0 Keycode = KeySemicolon | altgrMask | shiftMask // 176 ° DEGREE SIGN - ISO88591B1 Keycode = 0 // 177 ± PLUS-MINUS SIGN - ISO88591B2 Keycode = Key2 | altgrMask // 178 ² SUPERSCRIPT TWO - ISO88591B3 Keycode = Key3 | altgrMask // 179 ³ SUPERSCRIPT THREE - ISO88591B4 Keycode = KeyQuote | altgrMask // 180 ´ ACUTE ACCENT - ISO88591B5 Keycode = KeyM | altgrMask // 181 µ MICRO SIGN - ISO88591B6 Keycode = KeySemicolon | altgrMask // 182 ¶ PILCROW SIGN - ISO88591B7 Keycode = 0 // 183 · MIDDLE DOT - ISO88591B8 Keycode = 0 // 184 ¸ CEDILLA - ISO88591B9 Keycode = Key1 | altgrMask | shiftMask // 185 ¹ SUPERSCRIPT ONE - ISO88591BA Keycode = 0 // 186 º MASCULINE ORDINAL - ISO88591BB Keycode = KeyRightBrace | altgrMask // 187 » RIGHT DOUBLE ANGLE QUOTE - ISO88591BC Keycode = Key6 | altgrMask // 188 ¼ FRACTION ONE QUARTER - ISO88591BD Keycode = Key7 | altgrMask // 189 ½ FRACTION ONE HALF - ISO88591BE Keycode = Key8 | altgrMask // 190 ¾ FRACTION THREE QUARTERS - ISO88591BF Keycode = KeySlash | altgrMask // 191 ¿ INVERTED QUESTION MARK - ISO88591C0 Keycode = graveAccentBits | KeyA | shiftMask // 192 À A GRAVE - ISO88591C1 Keycode = KeyA | altgrMask | shiftMask // 193 Á A ACUTE - ISO88591C2 Keycode = circumflexBits | KeyA | shiftMask // 194 Â A CIRCUMFLEX - ISO88591C3 Keycode = tildeBits | KeyA | shiftMask // 195 Ã A TILDE - ISO88591C4 Keycode = KeyQ | altgrMask | shiftMask // 196 Ä A DIAERESIS - ISO88591C5 Keycode = KeyW | altgrMask | shiftMask // 197 Å A RING ABOVE - ISO88591C6 Keycode = KeyZ | altgrMask | shiftMask // 198 Æ AE - ISO88591C7 Keycode = KeyComma | altgrMask | shiftMask // 199 Ç C CEDILLA - ISO88591C8 Keycode = graveAccentBits | KeyE | shiftMask // 200 È E GRAVE - ISO88591C9 Keycode = KeyE | altgrMask | shiftMask // 201 É E ACUTE - ISO88591CA Keycode = circumflexBits | KeyE | shiftMask // 202 Ê E CIRCUMFLEX - ISO88591CB Keycode = diaeresisBits | KeyE | shiftMask // 203 Ë E DIAERESIS - ISO88591CC Keycode = graveAccentBits | KeyI | shiftMask // 204 Ì I GRAVE - ISO88591CD Keycode = KeyI | altgrMask | shiftMask // 205 Í I ACUTE - ISO88591CE Keycode = circumflexBits | KeyI | shiftMask // 206 Î I CIRCUMFLEX - ISO88591CF Keycode = diaeresisBits | KeyI | shiftMask // 207 Ï I DIAERESIS - ISO88591D0 Keycode = KeyD | altgrMask | shiftMask // 208 Ð ETH - ISO88591D1 Keycode = KeyN | altgrMask | shiftMask // 209 Ñ N TILDE - ISO88591D2 Keycode = graveAccentBits | KeyO | shiftMask // 210 Ò O GRAVE - ISO88591D3 Keycode = KeyO | altgrMask | shiftMask // 211 Ó O ACUTE - ISO88591D4 Keycode = circumflexBits | KeyO | shiftMask // 212 Ô O CIRCUMFLEX - ISO88591D5 Keycode = tildeBits | KeyO | shiftMask // 213 Õ O TILDE - ISO88591D6 Keycode = KeyP | altgrMask | shiftMask // 214 Ö O DIAERESIS - ISO88591D7 Keycode = KeyEqual | altgrMask // 215 × MULTIPLICATION - ISO88591D8 Keycode = KeyL | altgrMask | shiftMask // 216 Ø O STROKE - ISO88591D9 Keycode = graveAccentBits | KeyU | shiftMask // 217 Ù U GRAVE - ISO88591DA Keycode = KeyU | altgrMask | shiftMask // 218 Ú U ACUTE - ISO88591DB Keycode = circumflexBits | KeyU | shiftMask // 219 Û U CIRCUMFLEX - ISO88591DC Keycode = KeyY | altgrMask | shiftMask // 220 Ü U DIAERESIS - ISO88591DD Keycode = acuteAccentBits | KeyY | shiftMask // 221 Ý Y ACUTE - ISO88591DE Keycode = KeyT | altgrMask | shiftMask // 222 Þ THORN - ISO88591DF Keycode = KeyS | altgrMask // 223 ß SHARP S - ISO88591E0 Keycode = graveAccentBits | KeyA // 224 à a GRAVE - ISO88591E1 Keycode = KeyA | altgrMask // 225 á a ACUTE - ISO88591E2 Keycode = circumflexBits | KeyA // 226 â a CIRCUMFLEX - ISO88591E3 Keycode = tildeBits | KeyA // 227 ã a TILDE - ISO88591E4 Keycode = diaeresisBits | KeyA // 228 ä a DIAERESIS - ISO88591E5 Keycode = KeyW | altgrMask // 229 å a RING ABOVE - ISO88591E6 Keycode = KeyZ | altgrMask // 230 æ ae - ISO88591E7 Keycode = KeyComma | altgrMask // 231 ç c CEDILLA - ISO88591E8 Keycode = graveAccentBits | KeyE // 232 è e GRAVE - ISO88591E9 Keycode = acuteAccentBits | KeyE // 233 é e ACUTE - ISO88591EA Keycode = circumflexBits | KeyE // 234 ê e CIRCUMFLEX - ISO88591EB Keycode = diaeresisBits | KeyE // 235 ë e DIAERESIS - ISO88591EC Keycode = graveAccentBits | KeyI // 236 ì i GRAVE - ISO88591ED Keycode = KeyI | altgrMask // 237 í i ACUTE - ISO88591EE Keycode = circumflexBits | KeyI // 238 î i CIRCUMFLEX - ISO88591EF Keycode = diaeresisBits | KeyI // 239 ï i DIAERESIS - ISO88591F0 Keycode = KeyD | altgrMask // 240 ð ETH - ISO88591F1 Keycode = KeyN | altgrMask // 241 ñ n TILDE - ISO88591F2 Keycode = graveAccentBits | KeyO // 242 ò o GRAVE - ISO88591F3 Keycode = KeyO | altgrMask // 243 ó o ACUTE - ISO88591F4 Keycode = circumflexBits | KeyO // 244 ô o CIRCUMFLEX - ISO88591F5 Keycode = tildeBits | KeyO // 245 õ o TILDE - ISO88591F6 Keycode = KeyP | altgrMask // 246 ö o DIAERESIS - ISO88591F7 Keycode = KeyEqual | altgrMask | shiftMask // 247 ÷ DIVISION - ISO88591F8 Keycode = KeyL | altgrMask // 248 ø o STROKE - ISO88591F9 Keycode = graveAccentBits | KeyU // 249 ù u GRAVE - ISO88591FA Keycode = KeyU | altgrMask // 250 ú u ACUTE - ISO88591FB Keycode = circumflexBits | KeyU // 251 û u CIRCUMFLEX - ISO88591FC Keycode = KeyY | altgrMask // 252 ü u DIAERESIS - ISO88591FD Keycode = acuteAccentBits | KeyY // 253 ý y ACUTE - ISO88591FE Keycode = KeyT | altgrMask // 254 þ THORN - ISO88591FF Keycode = diaeresisBits | KeyY // 255 ÿ y DIAERESIS - UNICODE20AC Keycode = Key5 | altgrMask // 20AC € Euro Sign -) - -var ascii = [...]Keycode{ - ASCII00.mask(), ASCII01.mask(), ASCII02.mask(), ASCII03.mask(), - ASCII04.mask(), ASCII05.mask(), ASCII06.mask(), ASCII07.mask(), - ASCII08.mask(), ASCII09.mask(), ASCII0A.mask(), ASCII0B.mask(), - ASCII0C.mask(), ASCII0D.mask(), ASCII0E.mask(), ASCII0F.mask(), - ASCII10.mask(), ASCII11.mask(), ASCII12.mask(), ASCII13.mask(), - ASCII14.mask(), ASCII15.mask(), ASCII16.mask(), ASCII17.mask(), - ASCII18.mask(), ASCII19.mask(), ASCII1A.mask(), ASCII1B.mask(), - ASCII1C.mask(), ASCII1D.mask(), ASCII1E.mask(), ASCII1F.mask(), - ASCII20.mask(), ASCII21.mask(), ASCII22.mask(), ASCII23.mask(), - ASCII24.mask(), ASCII25.mask(), ASCII26.mask(), ASCII27.mask(), - ASCII28.mask(), ASCII29.mask(), ASCII2A.mask(), ASCII2B.mask(), - ASCII2C.mask(), ASCII2D.mask(), ASCII2E.mask(), ASCII2F.mask(), - ASCII30.mask(), ASCII31.mask(), ASCII32.mask(), ASCII33.mask(), - ASCII34.mask(), ASCII35.mask(), ASCII36.mask(), ASCII37.mask(), - ASCII38.mask(), ASCII39.mask(), ASCII3A.mask(), ASCII3B.mask(), - ASCII3C.mask(), ASCII3D.mask(), ASCII3E.mask(), ASCII3F.mask(), - ASCII40.mask(), ASCII41.mask(), ASCII42.mask(), ASCII43.mask(), - ASCII44.mask(), ASCII45.mask(), ASCII46.mask(), ASCII47.mask(), - ASCII48.mask(), ASCII49.mask(), ASCII4A.mask(), ASCII4B.mask(), - ASCII4C.mask(), ASCII4D.mask(), ASCII4E.mask(), ASCII4F.mask(), - ASCII50.mask(), ASCII51.mask(), ASCII52.mask(), ASCII53.mask(), - ASCII54.mask(), ASCII55.mask(), ASCII56.mask(), ASCII57.mask(), - ASCII58.mask(), ASCII59.mask(), ASCII5A.mask(), ASCII5B.mask(), - ASCII5C.mask(), ASCII5D.mask(), ASCII5E.mask(), ASCII5F.mask(), - ASCII60.mask(), ASCII61.mask(), ASCII62.mask(), ASCII63.mask(), - ASCII64.mask(), ASCII65.mask(), ASCII66.mask(), ASCII67.mask(), - ASCII68.mask(), ASCII69.mask(), ASCII6A.mask(), ASCII6B.mask(), - ASCII6C.mask(), ASCII6D.mask(), ASCII6E.mask(), ASCII6F.mask(), - ASCII70.mask(), ASCII71.mask(), ASCII72.mask(), ASCII73.mask(), - ASCII74.mask(), ASCII75.mask(), ASCII76.mask(), ASCII77.mask(), - ASCII78.mask(), ASCII79.mask(), ASCII7A.mask(), ASCII7B.mask(), - ASCII7C.mask(), ASCII7D.mask(), ASCII7E.mask(), ASCII7F.mask(), -} - -var iso88591 = [...]Keycode{ - ISO88591A0.mask(), ISO88591A1.mask(), ISO88591A2.mask(), ISO88591A3.mask(), - ISO88591A4.mask(), ISO88591A5.mask(), ISO88591A6.mask(), ISO88591A7.mask(), - ISO88591A8.mask(), ISO88591A9.mask(), ISO88591AA.mask(), ISO88591AB.mask(), - ISO88591AC.mask(), ISO88591AD.mask(), ISO88591AE.mask(), ISO88591AF.mask(), - ISO88591B0.mask(), ISO88591B1.mask(), ISO88591B2.mask(), ISO88591B3.mask(), - ISO88591B4.mask(), ISO88591B5.mask(), ISO88591B6.mask(), ISO88591B7.mask(), - ISO88591B8.mask(), ISO88591B9.mask(), ISO88591BA.mask(), ISO88591BB.mask(), - ISO88591BC.mask(), ISO88591BD.mask(), ISO88591BE.mask(), ISO88591BF.mask(), - ISO88591C0.mask(), ISO88591C1.mask(), ISO88591C2.mask(), ISO88591C3.mask(), - ISO88591C4.mask(), ISO88591C5.mask(), ISO88591C6.mask(), ISO88591C7.mask(), - ISO88591C8.mask(), ISO88591C9.mask(), ISO88591CA.mask(), ISO88591CB.mask(), - ISO88591CC.mask(), ISO88591CD.mask(), ISO88591CE.mask(), ISO88591CF.mask(), - ISO88591D0.mask(), ISO88591D1.mask(), ISO88591D2.mask(), ISO88591D3.mask(), - ISO88591D4.mask(), ISO88591D5.mask(), ISO88591D6.mask(), ISO88591D7.mask(), - ISO88591D8.mask(), ISO88591D9.mask(), ISO88591DA.mask(), ISO88591DB.mask(), - ISO88591DC.mask(), ISO88591DD.mask(), ISO88591DE.mask(), ISO88591DF.mask(), - ISO88591E0.mask(), ISO88591E1.mask(), ISO88591E2.mask(), ISO88591E3.mask(), - ISO88591E4.mask(), ISO88591E5.mask(), ISO88591E6.mask(), ISO88591E7.mask(), - ISO88591E8.mask(), ISO88591E9.mask(), ISO88591EA.mask(), ISO88591EB.mask(), - ISO88591EC.mask(), ISO88591ED.mask(), ISO88591EE.mask(), ISO88591EF.mask(), - ISO88591F0.mask(), ISO88591F1.mask(), ISO88591F2.mask(), ISO88591F3.mask(), - ISO88591F4.mask(), ISO88591F5.mask(), ISO88591F6.mask(), ISO88591F7.mask(), - ISO88591F8.mask(), ISO88591F9.mask(), ISO88591FA.mask(), ISO88591FB.mask(), - ISO88591FC.mask(), ISO88591FD.mask(), ISO88591FE.mask(), ISO88591FF.mask(), -} diff --git a/emb/machine/_usb/hid/mouse/mouse.go b/emb/machine/_usb/hid/mouse/mouse.go deleted file mode 100644 index d790bdb..0000000 --- a/emb/machine/_usb/hid/mouse/mouse.go +++ /dev/null @@ -1,148 +0,0 @@ -package mouse - -import ( - "machine" - "machine/usb/hid" -) - -var Mouse *mouse - -type Button byte - -const ( - Left Button = 1 << iota - Right - Middle - Back - Forward -) - -type mouse struct { - buf *hid.RingBuffer - button Button - waitTxc bool -} - -func init() { - if Mouse == nil { - Mouse = newMouse() - hid.SetHandler(Mouse) - } -} - -// New returns the USB hid-mouse port. -// Deprecated, better to just use Port() -func New() *mouse { - return Port() -} - -// Port returns the USB hid-mouse port. -func Port() *mouse { - return Mouse -} - -func newMouse() *mouse { - return &mouse{ - buf: hid.NewRingBuffer(), - } -} - -func (m *mouse) TxHandler() bool { - m.waitTxc = false - if b, ok := m.buf.Get(); ok { - m.waitTxc = true - hid.SendUSBPacket(b[:5]) - return true - } - return false -} - -func (m *mouse) RxHandler(b []byte) bool { - return false -} - -func (m *mouse) tx(b []byte) { - if machine.USBDev.InitEndpointComplete { - if m.waitTxc { - m.buf.Put(b) - } else { - m.waitTxc = true - hid.SendUSBPacket(b) - } - } -} - -// Move is a function that moves the mouse cursor. -func (m *mouse) Move(vx, vy int) { - if vx == 0 && vy == 0 { - return - } - - if vx < -128 { - vx = -128 - } - if vx > 127 { - vx = 127 - } - - if vy < -128 { - vy = -128 - } - if vy > 127 { - vy = 127 - } - - m.tx([]byte{ - 0x01, byte(m.button), byte(vx), byte(vy), 0x00, - }) -} - -// Click clicks the mouse button. -func (m *mouse) Click(btn Button) { - m.Press(btn) - m.Release(btn) -} - -// Press presses the given mouse buttons. -func (m *mouse) Press(btn Button) { - m.button |= btn - m.tx([]byte{ - 0x01, byte(m.button), 0x00, 0x00, 0x00, - }) -} - -// Release releases the given mouse buttons. -func (m *mouse) Release(btn Button) { - m.button &= ^btn - m.tx([]byte{ - 0x01, byte(m.button), 0x00, 0x00, 0x00, - }) -} - -// Wheel controls the mouse wheel. -func (m *mouse) Wheel(v int) { - if v == 0 { - return - } - - if v < -128 { - v = -128 - } - if v > 127 { - v = 127 - } - - m.tx([]byte{ - 0x01, byte(m.button), 0x00, 0x00, byte(v), - }) -} - -// WheelDown turns the mouse wheel down. -func (m *mouse) WheelDown() { - m.Wheel(-1) -} - -// WheelUp turns the mouse wheel up. -func (m *mouse) WheelUp() { - m.Wheel(1) -} diff --git a/emb/machine/_usb/msc/cbw.go b/emb/machine/_usb/msc/cbw.go deleted file mode 100644 index 7ebf346..0000000 --- a/emb/machine/_usb/msc/cbw.go +++ /dev/null @@ -1,62 +0,0 @@ -package msc - -import ( - "encoding/binary" - "machine/usb/msc/csw" - "machine/usb/msc/scsi" -) - -const ( - cbwMsgLen = 31 // Command Block Wrapper (CBW) message length - Signature = 0x43425355 // "USBC" in little endian -) - -type CBW struct { - HasCmd bool - Data []byte -} - -func (c *CBW) Tag() uint32 { - return binary.LittleEndian.Uint32(c.Data[4:8]) -} - -func (c *CBW) length() int { - return len(c.Data) -} - -func (c *CBW) validLength() bool { - return len(c.Data) == cbwMsgLen -} - -func (c *CBW) validSignature() bool { - return binary.LittleEndian.Uint32(c.Data[:4]) == Signature -} - -func (c *CBW) SCSICmd() scsi.Cmd { - return scsi.Cmd{Data: c.Data[15:]} -} - -func (c *CBW) transferLength() uint32 { - return binary.LittleEndian.Uint32(c.Data[8:12]) -} - -// isIn returns true if the command direction is from the device to the host. -func (c *CBW) isIn() bool { - return c.Data[12]>>7 != 0 -} - -// isOut returns true if the command direction is from the host to the device. -func (c *CBW) isOut() bool { - return !c.isIn() -} - -func (c *CBW) CSW(status csw.Status, residue uint32, b []byte) { - // Signature: "USBS" 53425355h (little endian) - binary.LittleEndian.PutUint32(b[:4], csw.Signature) - // Tag: (same as CBW) - copy(b[4:8], c.Data[4:8]) - // Data Residue: (untransferred bytes) - binary.LittleEndian.PutUint32(b[8:12], residue) - // Status: - b[12] = byte(status) -} diff --git a/emb/machine/_usb/msc/csw/csw.go b/emb/machine/_usb/msc/csw/csw.go deleted file mode 100644 index 29f44ef..0000000 --- a/emb/machine/_usb/msc/csw/csw.go +++ /dev/null @@ -1,14 +0,0 @@ -package csw - -type Status uint8 - -const ( - StatusPassed Status = iota - StatusFailed - StatusPhaseError -) - -const ( - MsgLen = 13 - Signature = 0x53425355 // "USBS" in little endian -) diff --git a/emb/machine/_usb/msc/disk.go b/emb/machine/_usb/msc/disk.go deleted file mode 100644 index 6624d38..0000000 --- a/emb/machine/_usb/msc/disk.go +++ /dev/null @@ -1,180 +0,0 @@ -package msc - -import ( - "encoding/binary" - "errors" - "fmt" - "machine" - "time" -) - -var ( - errWriteOutOfBounds = errors.New("WriteAt offset out of bounds") -) - -// RegisterBlockDevice registers a BlockDevice provider with the MSC driver -func (m *msc) RegisterBlockDevice(dev machine.BlockDevice) { - m.dev = dev - - if cap(m.blockCache) != int(dev.WriteBlockSize()) { - m.blockCache = make([]byte, dev.WriteBlockSize()) - m.buf = make([]byte, dev.WriteBlockSize()) - } - - m.blockSizeRaw = uint32(m.dev.WriteBlockSize()) - m.blockCount = uint32(m.dev.Size()) / m.blockSizeUSB - // Read/write/erase operations must be aligned to the underlying hardware blocks. In order to align - // them we assume the provided block device is aligned to the end of the underlying hardware block - // device and offset all reads/writes by the remaining bytes that don't make up a full block. - m.blockOffset = uint32(m.dev.Size()) % m.blockSizeUSB - // FIXME: Figure out what to do if the emulated write block size is larger than the erase block size - - // Set VPD UNMAP fields - for i := range vpdPages { - if vpdPages[i].PageCode == 0xb0 { - // 0xb0 - 5.4.5 Block Limits VPD page (B0h) - if len(vpdPages[i].Data) >= 28 { - // Set the OPTIMAL UNMAP GRANULARITY (write blocks per erase block) - granularity := uint32(dev.EraseBlockSize()) / m.blockSizeUSB - binary.BigEndian.PutUint32(vpdPages[i].Data[24:28], granularity) - } - if len(vpdPages[i].Data) >= 32 { - // Set the UNMAP GRANULARITY ALIGNMENT (first sector of first full erase block) - // The unmap granularity alignment is used to calculate an optimal unmap request starting LBA as follows: - // optimal unmap request starting LBA = (n * OPTIMAL UNMAP GRANULARITY) + UNMAP GRANULARITY ALIGNMENT - // where n is zero or any positive integer value - // https://www.seagate.com/files/staticfiles/support/docs/manual/Interface%20manuals/100293068j.pdf - - // We assume the block device is aligned to the end of the underlying block device - blockOffset := uint32(dev.EraseBlockSize()) % m.blockSizeUSB - // Set the UGAVALID bit to indicate that the UNMAP GRANULARITY ALIGNMENT is valid - blockOffset |= 0x80000000 - binary.BigEndian.PutUint32(vpdPages[i].Data[28:32], blockOffset) - } - break - } - } -} - -var _ machine.BlockDevice = (*RecorderDisk)(nil) - -// RecorderDisk is a block device that records actions taken on it -type RecorderDisk struct { - dev machine.BlockDevice - log []RecorderRecord - last time.Time - time time.Time -} - -type RecorderRecord struct { - OpCode RecorderOpCode - Offset int64 - Length int - Data []byte - Time int64 - valid bool -} - -type RecorderOpCode uint8 - -const ( - RecorderOpCodeRead RecorderOpCode = iota - RecorderOpCodeWrite - RecorderOpCodeEraseBlocks -) - -// NewRecorderDisk creates a new RecorderDisk instance -func NewRecorderDisk(dev machine.BlockDevice, count int) *RecorderDisk { - d := &RecorderDisk{ - dev: dev, - log: make([]RecorderRecord, 0, count), - last: time.Now(), - } - for i := 0; i < count; i++ { - d.log = append(d.log, RecorderRecord{ - OpCode: RecorderOpCodeRead, - Offset: 0, - Length: 0, - Data: make([]byte, dev.WriteBlockSize()), - Time: 0, - }) - } - return d -} - -func (d *RecorderDisk) Size() int64 { - return d.dev.Size() -} - -func (d *RecorderDisk) WriteBlockSize() int64 { - return d.dev.WriteBlockSize() -} - -func (d *RecorderDisk) EraseBlockSize() int64 { - return d.dev.EraseBlockSize() -} - -func (d *RecorderDisk) EraseBlocks(startBlock, numBlocks int64) error { - d.Record(RecorderOpCodeEraseBlocks, startBlock, int(numBlocks), []byte{}) - return d.dev.EraseBlocks(startBlock, numBlocks) -} - -func (d *RecorderDisk) ReadAt(buffer []byte, offset int64) (int, error) { - n, err := d.dev.ReadAt(buffer, offset) - d.Record(RecorderOpCodeRead, offset, n, buffer) - return n, err -} - -func (d *RecorderDisk) WriteAt(buffer []byte, offset int64) (int, error) { - n, err := d.dev.WriteAt(buffer, offset) - d.Record(RecorderOpCodeWrite, offset, n, buffer) - return n, err -} - -func (d *RecorderDisk) Record(opCode RecorderOpCode, offset int64, length int, data []byte) { - n := len(d.log) - 1 - // Shift the log entries up to make room for a new entry - for i := 0; i < n; i++ { - d.log[i].OpCode = d.log[i+1].OpCode - d.log[i].Offset = d.log[i+1].Offset - d.log[i].Length = d.log[i+1].Length - d.log[i].Data = d.log[i].Data[:len(d.log[i+1].Data)] - copy(d.log[i].Data, d.log[i+1].Data) - d.log[i].Time = d.log[i+1].Time - d.log[i].valid = d.log[i+1].valid - } - - // Append the new record - d.log[n].OpCode = opCode - d.log[n].Offset = offset - d.log[n].Length = length - d.log[n].Data = d.log[n].Data[:len(data)] - copy(d.log[n].Data, data) - d.log[n].Time = time.Since(d.time).Microseconds() - d.time = d.time.Add(time.Since(d.time)) - d.log[n].valid = true -} - -func (d *RecorderDisk) ClearLog() { - for i := range d.log { - d.log[i].valid = false - } - d.time = time.Now() -} - -func (d *RecorderDisk) GetLog() []RecorderRecord { - return d.log -} - -func (r *RecorderRecord) String() (string, bool) { - opCode := "Unknown" - switch r.OpCode { - case RecorderOpCodeRead: - opCode = "Read" - case RecorderOpCodeWrite: - opCode = "Write" - case RecorderOpCodeEraseBlocks: - opCode = "EraseBlocks" - } - return fmt.Sprintf("%s: %05d+%02d t:%d | % 0x", opCode, r.Offset, r.Length, r.Time, r.Data), r.valid -} diff --git a/emb/machine/_usb/msc/msc.go b/emb/machine/_usb/msc/msc.go deleted file mode 100644 index d3bf8d6..0000000 --- a/emb/machine/_usb/msc/msc.go +++ /dev/null @@ -1,299 +0,0 @@ -package msc - -import ( - "machine" - "machine/usb" - "machine/usb/descriptor" - "machine/usb/msc/csw" - "machine/usb/msc/scsi" - "time" -) - -type mscState uint8 - -const ( - mscStateCmd mscState = iota - mscStateData - mscStateStatus - mscStateStatusSent - mscStateNeedReset -) - -const ( - mscInterface = 2 -) - -var MSC *msc - -type msc struct { - buf []byte // Buffer for incoming/outgoing data - blockCache []byte // Buffer for block read/write data - taskQueued bool // Flag to indicate if the buffer has a task queued - rxStalled bool // Flag to indicate if the RX endpoint is stalled - txStalled bool // Flag to indicate if the TX endpoint is stalled - maxPacketSize uint32 // Maximum packet size for the IN endpoint - respStatus csw.Status // Response status for the last command - sendZLP bool // Flag to indicate if a zero-length packet should be sent before sending CSW - - cbw *CBW // Last received Command Block Wrapper - queuedBytes uint32 // Number of bytes queued for sending - sentBytes uint32 // Number of bytes sent - totalBytes uint32 // Total bytes to send - cswBuf []byte // CSW response buffer - state mscState - - maxLUN uint8 // Maximum Logical Unit Number (n-1 for n LUNs) - dev machine.BlockDevice - blockCount uint32 // Number of blocks in the device - blockOffset uint32 // Byte offset of the first block in the device for aligned writes - blockSizeUSB uint32 // Write block size as presented to the host over USB - blockSizeRaw uint32 // Write block size of the underlying device hardware - readOnly bool - - vendorID [8]byte // Max 8 ASCII characters - productID [16]byte // Max 16 ASCII characters - productRev [4]byte // Max 4 ASCII characters - - senseKey scsi.Sense - addlSenseCode scsi.SenseCode - addlSenseQualifier uint8 -} - -// Port returns the USB Mass Storage port -func Port(dev machine.BlockDevice) *msc { - if MSC == nil { - MSC = newMSC(dev) - } - return MSC -} - -func newMSC(dev machine.BlockDevice) *msc { - // Size our buffer to match the maximum packet size of the IN endpoint - maxPacketSize := descriptor.EndpointMSCIN.GetMaxPacketSize() - m := &msc{ - // Some platforms require reads/writes to be aligned to the full underlying hardware block - blockCache: make([]byte, dev.WriteBlockSize()), - blockSizeUSB: 512, - buf: make([]byte, dev.WriteBlockSize()), - cswBuf: make([]byte, csw.MsgLen), - cbw: &CBW{Data: make([]byte, 31)}, - maxPacketSize: uint32(maxPacketSize), - } - m.RegisterBlockDevice(dev) - - // Set default inquiry data fields - m.SetVendorID("TinyGo") - m.SetProductID("Mass Storage") - m.SetProductRev("1.0") - - // Initialize the USB Mass Storage Class (MSC) port - machine.ConfigureUSBEndpoint(descriptor.MSC, - []usb.EndpointConfig{ - { - Index: usb.MSC_ENDPOINT_IN, - IsIn: true, - Type: usb.ENDPOINT_TYPE_BULK, - TxHandler: txHandler, - StallHandler: setupPacketHandler, - }, - { - Index: usb.MSC_ENDPOINT_OUT, - IsIn: false, - Type: usb.ENDPOINT_TYPE_BULK, - DelayRxHandler: rxHandler, - StallHandler: setupPacketHandler, - }, - }, - []usb.SetupConfig{ - { - Index: mscInterface, - Handler: setupPacketHandler, - }, - }, - ) - - go m.processTasks() - - return m -} - -func (m *msc) processTasks() { - // Process tasks that cannot be done in an interrupt context - for { - if m.taskQueued { - cmd := m.cbw.SCSICmd() - switch cmd.CmdType() { - case scsi.CmdWrite: - m.scsiWrite(cmd, m.buf) - case scsi.CmdUnmap: - m.scsiUnmap(m.buf) - } - - // Acknowledge the received data from the host - m.queuedBytes = 0 - m.taskQueued = false - machine.AckUsbOutTransfer(usb.MSC_ENDPOINT_OUT) - } - time.Sleep(100 * time.Microsecond) - } -} - -func (m *msc) ready() bool { - return m.dev != nil -} - -func (m *msc) resetBuffer(length int) { - // Reset the buffer to the specified length - m.buf = m.buf[:length] - for i := 0; i < length; i++ { - m.buf[i] = 0 - } -} - -func (m *msc) sendUSBPacket(b []byte) { - if machine.USBDev.InitEndpointComplete { - // Send the USB packet - machine.SendUSBInPacket(usb.MSC_ENDPOINT_IN, b) - } -} - -func (m *msc) sendCSW(status csw.Status) { - // Generate CSW packet into m.cswBuf and send it - residue := uint32(0) - if m.totalBytes >= m.sentBytes { - residue = m.totalBytes - m.sentBytes - } - m.cbw.CSW(status, residue, m.cswBuf) - m.state = mscStateStatusSent - m.sendUSBPacket(m.cswBuf) -} - -func txHandler() { - if MSC != nil { - MSC.txHandler() - } -} - -func (m *msc) txHandler() { - m.run([]byte{}, false) -} - -func rxHandler(b []byte) bool { - ack := true - if MSC != nil { - ack = MSC.run(b, true) - } - return ack -} - -/* - Connection Happy Path Overview: - -0. MSC starts out in mscStateCmd status. - -1. Host sends CBW (Command Block Wrapper) packet to MSC. - - CBW contains the SCSI command to be executed, the length of the data to be transferred, etc. - -2. MSC receives CBW. - - CBW is validated and saved. - - State is changed to mscStateData. - - MSC routes the command to the appropriate SCSI command handler. - -3. The MSC SCSI command handler responds with the initial data packet (if applicable). - - If no data packet is needed, state is changed to mscStateStatus and step 4 is skipped. - -4. The host acks the data packet and MSC calls m.scsiDataTransfer() to continue sending (or -receiving) data. - - This cycle continues until all data requested in the CBW is sent/received. - - State is changed to mscStateStatus. - - MSC waits for the host to ACK the final data packet. - -5. MSC then sends a CSW (Command Status Wrapper) to the host to report the final status of the -command execution and moves to mscStateStatusSent. - -6. The host ACKs the CSW and the MSC moves back to mscStateCmd, waiting for the next CBW. -*/ -func (m *msc) run(b []byte, isEpOut bool) bool { - ack := true - - switch m.state { - case mscStateCmd: - // Receiving a new command block wrapper (CBW) - - // IN endpoint transfer complete confirmation, no action needed - if !isEpOut { - return ack - } - - // Create a temporary CBW wrapper to validate the incoming data. Has to be temporary - // to avoid it escaping into the heap since we're in interrupt context - cbw := CBW{Data: b} - - // Verify size and signature - if !cbw.validLength() || !cbw.validSignature() { - // 6.6.1 CBW Not Valid - // https://usb.org/sites/default/files/usbmassbulk_10.pdf - m.state = mscStateNeedReset - m.stallEndpoint(usb.MSC_ENDPOINT_IN) - m.stallEndpoint(usb.MSC_ENDPOINT_OUT) - m.stallEndpoint(usb.CONTROL_ENDPOINT) - return ack - } - - // Save the validated CBW for later reference - copy(m.cbw.Data, b) - - // Move on to the data transfer phase next go around (after sending the first message) - m.state = mscStateData - m.totalBytes = cbw.transferLength() - m.queuedBytes = 0 - m.sentBytes = 0 - m.respStatus = csw.StatusPassed - - m.scsiCmdBegin() - - case mscStateData: - // Transfer data - ack = m.scsiDataTransfer(b) - - case mscStateStatus: - // Sending CSW status response - // Placed after the switch statement so we can send the CSW without having to send a packet - // to cycle back through this block, e.g. with TEST UNIT READY which sends only a CSW after - // setting the sense key/add'l code/qualifier internally - - case mscStateStatusSent: - // Wait for the status phase to complete - if !isEpOut && m.queuedBytes == csw.MsgLen { - // Status confirmed sent, wait for next CBW - m.state = mscStateCmd - } else { - // We're not expecting any data here, ignore it. Original log line: - // TU_LOG1(" Warning expect SCSI Status but received unknown data\r\n"); - } - - case mscStateNeedReset: - // Received an invalid CBW message, stop everything until we get reset - } - - // Send CSW status response - // Placed after the switch statement so we can send the CSW without having to send a packet - // to cycle back through this block, e.g. with TEST UNIT READY which sends only a CSW after - // setting the sense key/add'l code/qualifier internally - if m.state == mscStateStatus && !m.txStalled { - if m.totalBytes > m.sentBytes && m.cbw.isIn() { - // 6.7.2 The Thirteen Cases - Case 5 (Hi > Di): STALL before status - m.stallEndpoint(usb.MSC_ENDPOINT_IN) - } else if m.sendZLP { - // Send a zero-length packet to force the end of the transfer before we send a CSW - m.queuedBytes = 0 - m.sendZLP = false - m.sendUSBPacket(m.buf[:0]) - } else { - m.sendCSW(m.respStatus) - m.state = mscStateCmd - } - } - - return ack -} diff --git a/emb/machine/_usb/msc/scsi.go b/emb/machine/_usb/msc/scsi.go deleted file mode 100644 index d7266ed..0000000 --- a/emb/machine/_usb/msc/scsi.go +++ /dev/null @@ -1,301 +0,0 @@ -package msc - -import ( - "encoding/binary" - "machine/usb" - "machine/usb/msc/csw" - "machine/usb/msc/scsi" -) - -func (m *msc) scsiCmdBegin() { - cmd := m.cbw.SCSICmd() - cmdType := cmd.CmdType() - - // Handle multi-packet commands - switch cmdType { - case scsi.CmdRead, scsi.CmdWrite: - m.scsiCmdReadWrite(cmd) - return - case scsi.CmdUnmap: - m.scsiCmdUnmap(cmd) - return - } - - if m.totalBytes > 0 && m.cbw.isOut() { - // Reject any other multi-packet commands - if m.totalBytes > m.maxPacketSize { - m.sendScsiError(csw.StatusFailed, scsi.SenseIllegalRequest, scsi.SenseCodeInvalidCmdOpCode) - return - } else { - // Original comment from TinyUSB: - // Didn't check for case 9 (Ho > Dn), which requires examining scsi command first - // but it is OK to just receive data then responded with failed status - } - } - switch cmdType { - case scsi.CmdTestUnitReady: - m.scsiTestUnitReady() - case scsi.CmdReadCapacity: - m.scsiCmdReadCapacity(cmd) - case scsi.CmdReadFormatCapacity: - m.scsiCmdReadFormatCapacity(cmd) - case scsi.CmdInquiry: - m.scsiCmdInquiry(cmd) - case scsi.CmdModeSense6, scsi.CmdModeSense10: - m.scsiCmdModeSense(cmd) - case scsi.CmdRequestSense: - m.scsiCmdRequestSense() - case scsi.CmdPreventAllowMediumRemoval: - m.scsiCmdPreventAllowMediumRemoval(cmd) - default: - // We don't support this command, error out - m.sendScsiError(csw.StatusFailed, scsi.SenseIllegalRequest, scsi.SenseCodeInvalidCmdOpCode) - } - - if len(m.buf) == 0 { - if m.totalBytes > 0 { - // 6.7.2 The Thirteen Cases - Case 4 (Hi > Dn) - // https://usb.org/sites/default/files/usbmassbulk_10.pdf - m.sendScsiError(csw.StatusFailed, scsi.SenseIllegalRequest, 0) - } else { - // 6.7.1 The Thirteen Cases - Case 1 Hn = Dn: all good - // https://usb.org/sites/default/files/usbmassbulk_10.pdf - m.state = mscStateStatus - } - } else { - if m.totalBytes == 0 { - // 6.7.1 The Thirteen Cases - Case 2 (Hn < Di) - // https://usb.org/sites/default/files/usbmassbulk_10.pdf - m.sendScsiError(csw.StatusFailed, scsi.SenseIllegalRequest, 0) - } else { - // Make sure we don't return more data than the host is expecting - if m.cbw.transferLength() < uint32(len(m.buf)) { - m.buf = m.buf[:m.cbw.transferLength()] - } - m.sendUSBPacket(m.buf) - } - } -} - -func (m *msc) scsiDataTransfer(b []byte) bool { - cmd := m.cbw.SCSICmd() - cmdType := cmd.CmdType() - - switch cmdType { - case scsi.CmdWrite, scsi.CmdUnmap: - if m.readOnly { - m.sendScsiError(csw.StatusFailed, scsi.SenseDataProtect, scsi.SenseCodeWriteProtected) - return true - } - return m.scsiQueueTask(cmdType, b) - } - - // Update our sent bytes count to include the just-confirmed bytes - m.sentBytes += m.queuedBytes - - if m.sentBytes >= m.totalBytes { - // Transfer complete, send CSW after transfer confirmed - m.state = mscStateStatus - } else if cmdType == scsi.CmdRead { - m.scsiRead(cmd) - } else { - // Other multi-packet commands are rejected in m.scsiCmdBegin() - } - - return true -} - -func (m *msc) scsiTestUnitReady() { - m.resetBuffer(0) - m.queuedBytes = 0 - - // Check if the device is ready - if !m.ready() { - // If not ready set sense data - m.senseKey = scsi.SenseNotReady - m.addlSenseCode = scsi.SenseCodeMediumNotPresent - m.addlSenseQualifier = 0x00 - } else { - m.senseKey = 0 - m.addlSenseCode = 0 - m.addlSenseQualifier = 0 - } -} - -func (m *msc) scsiCmdReadCapacity(cmd scsi.Cmd) { - m.resetBuffer(scsi.ReadCapacityRespLen) - m.queuedBytes = scsi.ReadCapacityRespLen - - // Last LBA address (big endian) - binary.BigEndian.PutUint32(m.buf[:4], m.blockCount-1) - // Block size (big endian) - binary.BigEndian.PutUint32(m.buf[4:8], m.blockSizeUSB) -} - -func (m *msc) scsiCmdReadFormatCapacity(cmd scsi.Cmd) { - m.resetBuffer(scsi.ReadFormatCapacityRespLen) - m.queuedBytes = scsi.ReadFormatCapacityRespLen - - // bytes 0-2 - reserved - m.buf[3] = 8 // Capacity list length - - // Number of blocks (big endian) - binary.BigEndian.PutUint32(m.buf[4:8], m.blockCount) - // Block size (24-bit, big endian) - binary.BigEndian.PutUint32(m.buf[8:12], m.blockSizeUSB) - // Descriptor Type - formatted media - m.buf[8] = 2 -} - -// MODE SENSE(6) / MODE SENSE(10) - Only used here to indicate that the device is write protected -func (m *msc) scsiCmdModeSense(cmd scsi.Cmd) { - respLen := uint32(scsi.ModeSense6RespLen) - if cmd.CmdType() == scsi.CmdModeSense10 { - respLen = scsi.ModeSense10RespLen - } - m.resetBuffer(int(respLen)) - m.queuedBytes = respLen - - // The host allows a good amount of leeway in response size - // Reset total bytes to what we'll actually send - if m.totalBytes > respLen { - m.totalBytes = respLen - m.sendZLP = true - } - - readOnly := byte(0) - if m.readOnly { - readOnly = 0x80 - } - - switch cmd.CmdType() { - case scsi.CmdModeSense6: - // byte 0 - Number of bytes after this one - m.buf[0] = byte(respLen) - 1 - // byte 1 - Medium type (0x00 for direct access block device) - // Bit 7 indicates write protected - m.buf[2] = readOnly - // byte 3 - Block descriptor length: 0 (not supported) - case scsi.CmdModeSense10: - // bytes 0-1 - Number of bytes after this one - m.buf[1] = byte(respLen) - 2 - // byte 2 - Medium type (0x00 for direct access block device) - // Bit 7 indicates write protected - m.buf[3] = readOnly - } -} - -// PREVENT/ALLOW MEDIUM REMOVAL - A flash drive doesn't have a removable medium, so this is a no-op -func (m *msc) scsiCmdPreventAllowMediumRemoval(cmd scsi.Cmd) { - m.resetBuffer(0) - m.queuedBytes = 0 - - // Check if the device is ready - if !m.ready() { - // If not ready set sense data - m.senseKey = scsi.SenseNotReady - m.addlSenseCode = scsi.SenseCodeMediumNotPresent - m.addlSenseQualifier = 0x00 - } else { - m.senseKey = 0 - m.addlSenseCode = 0 - m.addlSenseQualifier = 0 - } - - m.state = mscStateStatus -} - -// REQUEST SENSE - Returns error status codes when an error status is sent -func (m *msc) scsiCmdRequestSense() { - // Set the buffer size to the SCSI sense message size and clear - m.resetBuffer(scsi.RequestSenseRespLen) - m.queuedBytes = scsi.RequestSenseRespLen - m.totalBytes = scsi.RequestSenseRespLen - - // 0x70 - current error, 0x71 - deferred error (not used) - m.buf[0] = 0xF0 // 0x70 for current error plus 0x80 for valid flag bit - // byte 1 - reserved - m.buf[2] = uint8(m.senseKey) & 0x0F // Incorrect Length Indicator bit not supported - // bytes 3-6 - Information (not used) - // byte 7 - Additional Sense Length (bytes remaining in the message) - m.buf[7] = scsi.RequestSenseRespLen - 8 - // bytes 8-11 - Command Specific Information (not used) - m.buf[12] = byte(m.addlSenseCode) // Additional Sense Code (optional) - m.buf[13] = m.addlSenseQualifier // Additional Sense Code Qualifier (optional) - // bytes 14-17 - reserved - - // Clear sense data after copied to buffer - m.senseKey = 0 - m.addlSenseCode = 0 - m.addlSenseQualifier = 0 -} - -func (m *msc) scsiCmdUnmap(cmd scsi.Cmd) { - // Unmap sends a header in the CBW and a parameter list in the data stage - // The parameter list has an 8 byte header and 16 bytes per item. If it's less than 24 bytes it's - // not the format we're expecting and we won't be able to decode it. Same for if there isn't a - // 8 byte header plus multiples of 16 bytes after that - paramLen := binary.BigEndian.Uint16(m.cbw.Data[7:9]) - if paramLen < 24 || (paramLen-8)%16 != 0 { - m.sendScsiError(csw.StatusFailed, scsi.SenseIllegalRequest, scsi.SenseCodeInvalidFieldInCDB) - return - } -} - -func (m *msc) scsiQueueTask(cmdType scsi.CmdType, b []byte) bool { - // Check if the incoming data is larger than our buffer - if int(m.queuedBytes)+len(b) > cap(m.buf) { - m.sendScsiError(csw.StatusFailed, scsi.SenseIllegalRequest, scsi.SenseCodeInvalidFieldInCDB) - return true - } - - // Save the incoming data in our buffer for processing outside of interrupt context. - if m.taskQueued { - // If we already have a full task queue we can't accept this data - m.sendScsiError(csw.StatusFailed, scsi.SenseAbortedCommand, scsi.SenseCodeMsgReject) - return true - } - - // Copy the queued task data into our buffer - start := m.queuedBytes - end := start + uint32(len(b)) - m.buf = m.buf[:end] - copy(m.buf[start:end], b) - m.queuedBytes += uint32(len(b)) - - switch cmdType { - case scsi.CmdWrite: - // If we're writing data wait until we have a full write block of data that can be processed. - if m.queuedBytes == uint32(cap(m.blockCache)) { - m.taskQueued = true - } - case scsi.CmdUnmap: - m.taskQueued = true - } - - // Don't acknowledge the incoming data until we can process it. - return !m.taskQueued -} - -func (m *msc) sendScsiError(status csw.Status, key scsi.Sense, code scsi.SenseCode) { - // Generate CSW into m.cswBuf - residue := m.totalBytes - m.sentBytes - - // Prepare to send CSW - m.sendZLP = true // Ensure the transaction is signaled as ended before a CSW is sent - m.respStatus = status - m.state = mscStateStatus - - // Set the sense data - m.senseKey = key - m.addlSenseCode = code - m.addlSenseQualifier = 0x00 // Not used - - if m.totalBytes > 0 && residue > 0 { - if m.cbw.isIn() { - m.stallEndpoint(usb.MSC_ENDPOINT_IN) - } else { - m.stallEndpoint(usb.MSC_ENDPOINT_OUT) - } - } -} diff --git a/emb/machine/_usb/msc/scsi/scsi.go b/emb/machine/_usb/msc/scsi/scsi.go deleted file mode 100644 index 5b63f67..0000000 --- a/emb/machine/_usb/msc/scsi/scsi.go +++ /dev/null @@ -1,140 +0,0 @@ -package scsi - -import ( - "encoding/binary" - "fmt" -) - -type Cmd struct { - Data []byte -} - -func (c *Cmd) CmdType() CmdType { - return CmdType(c.Data[0]) -} - -func (c *Cmd) BlockCount() uint32 { - return uint32(binary.BigEndian.Uint16(c.Data[7:9])) -} - -func (c *Cmd) LBA() uint32 { - return binary.BigEndian.Uint32(c.Data[2:6]) -} - -func (c Cmd) String() string { - cmdType := c.CmdType() - switch cmdType { - case CmdRead: - return fmt.Sprintf("%-28s LBA: % 3d, Block Count: %d", cmdType, c.LBA(), c.BlockCount()) - case CmdWrite: - return fmt.Sprintf("%-28s LBA: % 3d, Block Count: %d", cmdType, c.LBA(), c.BlockCount()) - default: - return fmt.Sprintf("%-28s % x", cmdType, c.Data) - } -} - -type CmdType uint8 - -const ( - CmdTestUnitReady CmdType = 0x00 // TEST UNIT READY is used to determine if a device is ready to transfer data (read/write). The device does not perform a self-test operation - CmdRequestSense CmdType = 0x03 // REQUEST SENSE returns the current sense data (status or error information) - CmdInquiry CmdType = 0x12 // INQUIRY is used to obtain basic information from a target device - CmdModeSelect6 CmdType = 0x15 // MODE SELECT (6) provides a means for the application client to specify medium, logical unit, or peripheral device parameters to the device server - CmdModeSelect10 CmdType = 0x55 // MODE SELECT (10) provides a means for the application client to specify medium, logical unit, or peripheral device parameters to the device server - CmdModeSense6 CmdType = 0x1A // MODE SENSE (6) provides a means for a device server to report parameters to an application client - CmdModeSense10 CmdType = 0x5A // MODE SENSE (10) provides a means for a device server to report parameters to an application client with 64-bit logical block addressing - CmdStartStopUnit CmdType = 0x1B // START STOP UNIT is used to start or stop the medium in a device server - CmdPreventAllowMediumRemoval CmdType = 0x1E // PREVENT ALLOW MEDIUM REMOVAL is used to prevent or allow the removal of storage medium from a device server - CmdReadFormatCapacity CmdType = 0x23 // READ FORMAT CAPACITY allows the Host to request a list of the possible format capacities for an installed writable media - CmdReadCapacity CmdType = 0x25 // READ CAPACITY command is used to obtain data capacity information from a target device - CmdRead CmdType = 0x28 // READ (10) requests that the device server read the specified logical block(s) and transfer them to the data-in buffer - CmdWrite CmdType = 0x2A // WRITE (10) requests that the device server transfer the specified logical block(s) from the data-out buffer and write them - CmdUnmap CmdType = 0x42 // UNMAP command is used to inform the device server that the specified logical block(s) are no longer in use -) - -func (c CmdType) String() string { - switch c { - case CmdTestUnitReady: - return "TEST UNIT READY" - case CmdRequestSense: - return "REQUEST SENSE" - case CmdInquiry: - return "INQUIRY" - case CmdModeSelect6: - return "MODE SELECT (6)" - case CmdModeSelect10: - return "MODE SELECT (10)" - case CmdModeSense6: - return "MODE SENSE (6)" - case CmdModeSense10: - return "MODE SENSE (10)" - case CmdStartStopUnit: - return "START STOP UNIT" - case CmdPreventAllowMediumRemoval: - return "PREVENT ALLOW MEDIUM REMOVAL" - case CmdReadFormatCapacity: - return "READ FORMAT CAPACITY" - case CmdReadCapacity: - return "READ CAPACITY" - case CmdRead: - return "READ (10)" - case CmdWrite: - return "WRITE (10)" - case CmdUnmap: - return "UNMAP" - default: - return fmt.Sprintf("Unknown Command (0x%0x)", byte(c)) - } -} - -type Sense uint8 - -const ( - // 4.5.6 Sense key and sense code definitions - // https://www.t10.org/ftp/t10/document.08/08-309r0.pdf - SenseNone Sense = 0x00 // No specific Sense Key. This indicates no error condition - SenseRecoveredError Sense = 0x01 // The last command completed successfully, but with some recovery action performed - SenseNotReady Sense = 0x02 // The LUN addressed is not ready to be accessed - SenseMediumError Sense = 0x03 // The command terminated with an unrecoverable error condition - SenseHardwareError Sense = 0x04 // The drive detected an unrecoverable hardware failure while performing the command or during a self test - SenseIllegalRequest Sense = 0x05 // An illegal parameter was provided in the command descriptor block or the additional parameters - SenseUnitAttention Sense = 0x06 // The disk drive may have been reset - SenseDataProtect Sense = 0x07 // A read or write command was attempted on a block that is protected from this operation and was not performed - SenseBlankCheck Sense = 0x08 // A write-once device or a sequential-access device encountered blank medium or format-defined end-of-data indication while reading or that a write-once device encountered a non-blank medium while writing - SenseFirmwareError Sense = 0x09 // Vendor specific sense key - SenseAbortedCommand Sense = 0x0B // The disk drive aborted the command - SenseVolumeOverflow Sense = 0x0D // A buffered peripheral device has reached the end of medium partition and data remains in the buffer that has not been written to the medium - SenseMiscompare Sense = 0x0E // The source data did not match the data read from the medium -) - -type SenseCode uint8 - -const ( - // SenseNotReady - SenseCodeMediumNotPresent SenseCode = 0x3A // The storage medium is not present in the device (e.g. empty CD-ROM drive or flash card reader) - - // SenseIllegalRequest - SenseCodeInvalidCmdOpCode SenseCode = 0x20 // The command operation code is not supported by the device - SenseCodeInvalidFieldInCDB SenseCode = 0x24 // The command descriptor block (CDB) contains an invalid field - - // SenseDataProtect - SenseCodeWriteProtected SenseCode = 0x27 // The media is write protected - - // SenseAbortedCommand - SenseCodeLUNCommFailure SenseCode = 0x08 // LUN communication failure - SenseCodeAbortedCmd SenseCode = 0x0B // The command was aborted by the device - SenseCodeMsgReject SenseCode = 0x43 // The command was rejected by the device - SenseCodeOverlapCmdAttempted SenseCode = 0x4E // The command was rejected by the device because it was overlapped by another command - - // SenseVolumeOverflow - SenseCodeLBAOutOfRange SenseCode = 0x21 // The logical block address (LBA) is beyond the end of the volume -) - -const ( - InquiryRespLen = 36 - ModeSense6RespLen = 4 - ModeSense10RespLen = 8 - ReadCapacityRespLen = 8 - ReadFormatCapacityRespLen = 12 - RequestSenseRespLen = 18 -) diff --git a/emb/machine/_usb/msc/scsi_inquiry.go b/emb/machine/_usb/msc/scsi_inquiry.go deleted file mode 100644 index ae7028f..0000000 --- a/emb/machine/_usb/msc/scsi_inquiry.go +++ /dev/null @@ -1,164 +0,0 @@ -package msc - -import ( - "encoding/binary" - "machine/usb/msc/csw" - "machine/usb/msc/scsi" -) - -type vpdPage struct { - PageCode uint8 - PageLength uint8 - // Page data - // First four bytes are always Device Type, Page Code, and Page Length (2 bytes) and are omitted here - Data []byte -} - -// These must be sorted in ascending order by PageCode -var vpdPages = []vpdPage{ - { - // 0xb0 - 5.4.5 Block Limits VPD page (B0h) - // https://www.seagate.com/files/staticfiles/support/docs/manual/Interface%20manuals/100293068j.pdf - PageCode: 0xb0, - PageLength: 0x3c, // 60 bytes - Data: []byte{ - 0x00, 0x00, // WSNZ, MAXIMUM COMPARE AND WRITE LENGTH - Not supported - 0x00, 0x00, // OPTIMAL TRANSFER LENGTH GRANULARITY - Not supported - 0x00, 0x00, 0x00, 0x00, // MAXIMUM TRANSFER LENGTH - Not supported - 0x00, 0x00, 0x00, 0x00, // OPTIMAL TRANSFER LENGTH - Not supported - 0x00, 0x00, 0x00, 0x00, // MAXIMUM PREFETCH LENGTH - Not supported - 0xFF, 0xFF, 0xFF, 0xFF, // MAXIMUM UNMAP LBA COUNT - Maximum count supported - 0x00, 0x00, 0x00, 0x03, // MAXIMUM UNMAP BLOCK DESCRIPTOR COUNT - Max 3 descriptors - 0x00, 0x00, 0x00, 0x00, // OPTIMAL UNMAP GRANULARITY - 0x00, 0x00, 0x00, 0x00, // UNMAP GRANULARITY ALIGNMENT (bit 7 on byte 28 sets UGAVALID) - // From here on all bytes are zero and can be omitted from the response - // 0x00, 0x00, 0x00, 0x00, // MAXIMUM WRITE SAME LENGTH - Not supported - // 0x00, 0x00, 0x00, 0x00, // (8-bytes) - // 0x00, 0x00, 0x00, 0x00, // MAXIMUM ATOMIC TRANSFER LENGTH - Not supported - // 0x00, 0x00, 0x00, 0x00, // ATOMIC ALIGNMENT - Not supported - // 0x00, 0x00, 0x00, 0x00, // ATOMIC TRANSFER LENGTH GRANULARITY - Not supported - // 0x00, 0x00, 0x00, 0x00, // MAXIMUM ATOMIC TRANSFER LENGTH WITH ATOMIC BOUNDARY - Not supported - // 0x00, 0x00, 0x00, 0x00, // MAXIMUM ATOMIC BOUNDARY SIZE - Not supported - }, - }, - { - // 0xb1 - 5.4.3 Block Device Characteristics VPD page (B1h) - // https://www.seagate.com/files/staticfiles/support/docs/manual/Interface%20manuals/100293068j.pdf - PageCode: 0xb1, - PageLength: 0x3c, // 60 bytes (bytes 9+ are all reserved/zero) - Data: []byte{ - 0x00, 0x01, // Rotation rate (0x0001 - non-rotating medium) - 0x00, // Product type - 0x00: Not indicated, 0x04: MMC/eMMC, 0x05: SD card - 0x00, // WABEREQ/WACEREQ/Form Factor - Not specified - 0x00, // ZBC/BOCS/FUAB/VBULS - // Reserved (55 bytes) - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, - }, - }, - { - // 0xb2 - 5.4.13 Logical Block Provisioning VPD page (B2h) - // https://www.seagate.com/files/staticfiles/support/docs/manual/Interface%20manuals/100293068j.pdf - PageCode: 0xB2, - PageLength: 0x04, - Data: []byte{ - 0x00, // Logical Block Provisioning Threshold Exponent - 0x80, // 0x80 - LBPU (UNMAP command supported) - 0x00, // Minimum percentage/Provisioning type - Not specified - 0x00, // Threshold percentage - Not supported - }, - }, -} - -func (m *msc) scsiCmdInquiry(cmd scsi.Cmd) { - evpd := cmd.Data[1] & 0x01 - pageCode := cmd.Data[2] - - // PAGE CODE (byte 2) can't be set if the EVPD bit is not set - if evpd == 0 { - if pageCode == 0 { - // Standard INQUIRY command - m.scsiStdInquiry(cmd) - } else { - // 3.6.1 INQUIRY command introduction - // https://www.seagate.com/files/staticfiles/support/docs/manual/Interface%20manuals/100293068j.pdf - m.sendScsiError(csw.StatusFailed, scsi.SenseIllegalRequest, scsi.SenseCodeInvalidFieldInCDB) - return - } - } else { - m.scsiEvpdInquiry(cmd, pageCode) - } -} - -func (m *msc) scsiEvpdInquiry(cmd scsi.Cmd, pageCode uint8) { - var pageLength int - switch pageCode { - case 0x00: - // 5.4.18 Supported Vital Product Data pages (00h) - // https://www.seagate.com/files/staticfiles/support/docs/manual/Interface%20manuals/100293068j.pdf - - pageLength = len(vpdPages) + 1 // Number of pages + 1 for 0x00 (excluded from vpdPages[]) - m.resetBuffer(pageLength + 4) // n+4 supported VPD pages - // bytes 4+ - Supported VPD pages in ascending order - for i := 0; i < len(vpdPages); i++ { - m.buf[4+i] = vpdPages[i].PageCode - } - default: - found := false - for i := range vpdPages { - if vpdPages[i].PageCode == pageCode { - // Our advertised page length is "for entertainment use only". Some pages have dozens of - // reserved (zero) bytes at the end that don't actually need to be sent. If we omit them - // from our response they are (correctly) presumed to be zero bytes by the host - pageLength = int(vpdPages[i].PageLength) - // We actually just send the length of the bytes we have plus the same four byte header, - // but declare the length of the response according to the spec as appropriate - m.resetBuffer(len(vpdPages[i].Data) + 4) - copy(m.buf[4:], vpdPages[i].Data) - found = true - break - } - } - if !found { - // VPD page not found, send error - m.sendScsiError(csw.StatusFailed, scsi.SenseIllegalRequest, scsi.SenseCodeInvalidFieldInCDB) - return - } - } - - // byte 0 - Peripheral Qualifier/Peripheral Device Type (0x00 for direct access block device) - m.buf[1] = pageCode - binary.BigEndian.PutUint16(m.buf[2:4], uint16(pageLength)) - - // Set total bytes to the length of our response - m.queuedBytes = uint32(len(m.buf)) - m.totalBytes = uint32(len(m.buf)) -} - -func (m *msc) scsiStdInquiry(cmd scsi.Cmd) { - m.resetBuffer(scsi.InquiryRespLen) - m.queuedBytes = scsi.InquiryRespLen - m.totalBytes = scsi.InquiryRespLen - - // byte 0 - Device Type (0x00 for direct access block device) - // byte 1 - Removable media bit - m.buf[1] = 0x80 - // byte 2 - Version 0x00 - We claim conformance to no standard - // byte 3 - Response data format - m.buf[3] = 2 - // byte 4 - Additional length (number of bytes after this one) - m.buf[4] = scsi.InquiryRespLen - 5 - // byte 5 - Not used - // byte 6 - Not used - // byte 7 - Not used - // bytes 8-15 - Vendor ID - copy(m.buf[8:16], m.vendorID[:]) - // bytes 16-31 - Product ID - copy(m.buf[16:32], m.productID[:]) - // bytes 32-35 - Product revision level - copy(m.buf[32:36], m.productRev[:]) -} diff --git a/emb/machine/_usb/msc/scsi_readwrite.go b/emb/machine/_usb/msc/scsi_readwrite.go deleted file mode 100644 index 1b09e13..0000000 --- a/emb/machine/_usb/msc/scsi_readwrite.go +++ /dev/null @@ -1,144 +0,0 @@ -package msc - -import ( - "errors" - "machine/usb/msc/csw" - "machine/usb/msc/scsi" -) - -var invalidWriteError = errors.New("invalid write offset or length") - -func (m *msc) scsiCmdReadWrite(cmd scsi.Cmd) { - status := m.validateScsiReadWrite(cmd) - if status != csw.StatusPassed { - m.sendScsiError(status, scsi.SenseIllegalRequest, scsi.SenseCodeInvalidCmdOpCode) - } else if m.totalBytes > 0 { - if cmd.CmdType() == scsi.CmdRead { - m.scsiRead(cmd) - } else { - // WRITE(10) and UNMAP commands don't take any action until the data stage begins - } - } else { - // Zero byte transfer. No practical use case - m.state = mscStateStatus - } -} - -// Validate SCSI READ(10) and WRITE(10) commands -func (m *msc) validateScsiReadWrite(cmd scsi.Cmd) csw.Status { - blockCount := cmd.BlockCount() - // CBW wrapper transfer length - if m.totalBytes == 0 { - // If the SCSI command's block count doesn't loosely match the wrapper's transfer length something's wrong - if blockCount > 0 { - return csw.StatusPhaseError - } - // Zero length transfer. No practical use case, but explicitly not an error according to the spec - return csw.StatusPassed - } - if (cmd.CmdType() == scsi.CmdRead && m.cbw.isOut()) || (cmd.CmdType() == scsi.CmdWrite && m.cbw.isIn()) { - // If the command is READ(10) and the data direction is from host to device that's a problem - // 6.7.3 The Thirteen Cases - Case 10 (Ho <> Di) - // If the command is WRITE(10) and the data direction is from device to host that's also a problem - // 6.7.2 The Thirteen Cases - Case 8 (Hi <> Do) - // https://usb.org/sites/default/files/usbmassbulk_10.pdf - return csw.StatusPhaseError - } - if blockCount == 0 { - // We already checked for zero length transfer above, so this is a problem - // 6.7.2 The Thirteen Cases - Case 4 (Hi > Dn) - // https://usb.org/sites/default/files/usbmassbulk_10.pdf - return csw.StatusFailed - } - if m.totalBytes/blockCount == 0 { - // Block size shouldn't be small enough to round to zero - // 6.7.2 The Thirteen Cases - Case 7 (Hi < Di) READ(10) or - // 6.7.3 The Thirteen Cases - Case 13 (Ho < Do) WRITE(10) - // https://usb.org/sites/default/files/usbmassbulk_10.pdf - return csw.StatusPhaseError - } - return csw.StatusPassed -} - -func (m *msc) usbToRawOffset(lba, offset uint32) (int64, int64) { - // Convert the emulated block address to the underlying hardware block's start and offset - rawLBA := (lba*m.blockSizeUSB + offset) / m.blockSizeRaw - rawBlockOffset := int64((lba*m.blockSizeUSB + offset) % m.blockSizeRaw) - return int64(m.blockOffset + rawLBA*m.blockSizeRaw), rawBlockOffset -} - -func (m *msc) readBlock(b []byte, lba, offset uint32) (n int, err error) { - // Convert the emulated block address to the underlying hardware block's start and offset - blockStart, blockOffset := m.usbToRawOffset(lba, offset) - - // Read a full block from the underlying device into the block cache - n, err = m.dev.ReadAt(m.blockCache, blockStart) - n -= int(blockOffset) - if n > len(b) { - n = len(b) - } - - copy(b, m.blockCache[blockOffset:]) - - return n, err -} - -func (m *msc) writeBlock(b []byte, lba, offset uint32) (n int, err error) { - // Convert the emulated block address to the underlying hardware block's start and offset - blockStart, blockOffset := m.usbToRawOffset(lba, offset) - - if blockOffset != 0 || len(b) != int(m.blockSizeRaw) { - return 0, invalidWriteError - } - - // Write the full block to the underlying device - n, err = m.dev.WriteAt(b, blockStart) - n -= int(blockOffset) - if n > len(b) { - n = len(b) - } - - return n, err -} - -func (m *msc) scsiRead(cmd scsi.Cmd) { - // Make sure we don't exceed the buffer size - readEnd := m.totalBytes - m.sentBytes - if readEnd > m.maxPacketSize { - readEnd = m.maxPacketSize - } - // Resize the buffer to fit the read size - m.resetBuffer(int(readEnd)) - - // Read data from the emulated block device - n, err := m.readBlock(m.buf[:readEnd], cmd.LBA(), m.sentBytes) - if err != nil || n == 0 { - m.sendScsiError(csw.StatusFailed, scsi.SenseNotReady, scsi.SenseCodeMediumNotPresent) - return - } - - m.queuedBytes = readEnd - m.sendUSBPacket(m.buf) -} - -func (m *msc) scsiWrite(cmd scsi.Cmd, b []byte) { - if m.readOnly { - m.sendScsiError(csw.StatusFailed, scsi.SenseDataProtect, scsi.SenseCodeWriteProtected) - return - } - - // Write data to the block device - n, err := m.writeBlock(b, cmd.LBA(), m.sentBytes) - if err != nil || n < len(b) { - m.sentBytes += uint32(n) - m.sendScsiError(csw.StatusFailed, scsi.SenseNotReady, scsi.SenseCodeMediumNotPresent) - } else { - m.sentBytes += uint32(len(b)) - } - - if m.sentBytes >= m.totalBytes { - // Data transfer is complete, send CSW - m.state = mscStateStatus - m.run([]byte{}, true) - } -} diff --git a/emb/machine/_usb/msc/scsi_unmap.go b/emb/machine/_usb/msc/scsi_unmap.go deleted file mode 100644 index 79c2426..0000000 --- a/emb/machine/_usb/msc/scsi_unmap.go +++ /dev/null @@ -1,91 +0,0 @@ -package msc - -import ( - "encoding/binary" - "machine/usb/msc/csw" - "machine/usb/msc/scsi" -) - -type Error int - -const ( - errorLBAOutOfRange Error = iota -) - -func (e Error) Error() string { - switch e { - case errorLBAOutOfRange: - return "LBA out of range" - default: - return "unknown error" - } -} - -func (m *msc) scsiUnmap(b []byte) { - // Execute Order 66 (0x42) to wipe out the blocks - // 3.54 Unmap Command (SBC-4) - // https://www.seagate.com/files/staticfiles/support/docs/manual/Interface%20manuals/100293068j.pdf - if m.readOnly { - m.sendScsiError(csw.StatusFailed, scsi.SenseDataProtect, scsi.SenseCodeWriteProtected) - return - } - - // blockDescLen is the remaining length of block descriptors in the message, offset 8 bytes from - // the start of this packet - var blockDescLen uint16 - - // Decode the parameter list - msgLen := binary.BigEndian.Uint16(b[:2]) - // Length of the block descriptor portion of the message - blockDescLen = binary.BigEndian.Uint16(b[2:4]) - // Do some sanity checks on the message lengths (max 3 block descriptors to fit in one 64 byte packet) - if msgLen < 8 || blockDescLen < 16 || msgLen-blockDescLen != 6 || blockDescLen > (3*16) { - m.sendScsiError(csw.StatusFailed, scsi.SenseIllegalRequest, scsi.SenseCodeInvalidFieldInCDB) - return - } - - // descEnd marks the end of the last full block descriptor in this packet - descEnd := int(blockDescLen + 8) - - // Unmap the blocks we can from this packet - for i := 8; i < descEnd; i += 16 { - err := m.unmapBlocksFromDescriptor(b[i:], uint64(m.blockCount)) - if err != nil { - // TODO: Might need a better error code here for device errors? - m.sendScsiError(csw.StatusFailed, scsi.SenseVolumeOverflow, scsi.SenseCodeLBAOutOfRange) - return - } - } - - // FIXME: We need to handle erase block alignment - - m.sentBytes += uint32(len(b)) - if m.sentBytes >= m.totalBytes { - // Order 66 complete, send CSW to establish galactic empire - m.state = mscStateStatus - m.run([]byte{}, true) - } -} - -func (m *msc) unmapBlocksFromDescriptor(b []byte, numBlocks uint64) error { - blockCount := binary.BigEndian.Uint32(b[8:12]) - if blockCount == 0 { - // No blocks to unmap. Explicitly not an error per the spec - return nil - } - // This is technically a 64-bit LBA, but we can't address that many bytes - // let alone blocks, so we just use the lower 32 bits - lba := binary.BigEndian.Uint32(b[4:8]) - - // Make sure the unmap command doesn't extend past the end of the volume - if lba+blockCount > m.blockCount { - return errorLBAOutOfRange - } - - // Convert the emulated block size to the underlying hardware erase block size - blockStart := int64(lba*m.blockSizeUSB) / m.dev.EraseBlockSize() - rawBlockCount := int64(blockCount*m.blockSizeUSB) / m.dev.EraseBlockSize() - - // Unmap the blocks - return m.dev.EraseBlocks(blockStart, rawBlockCount) -} diff --git a/emb/machine/_usb/msc/setup.go b/emb/machine/_usb/msc/setup.go deleted file mode 100644 index 3d5bef2..0000000 --- a/emb/machine/_usb/msc/setup.go +++ /dev/null @@ -1,172 +0,0 @@ -package msc - -import ( - "machine" - "machine/usb" - "machine/usb/msc/csw" -) - -func setupPacketHandler(setup usb.Setup) bool { - if MSC != nil { - return MSC.setupPacketHandler(setup) - } - return false -} - -func (m *msc) setupPacketHandler(setup usb.Setup) bool { - ok := false - wValue := (uint16(setup.WValueH) << 8) | uint16(setup.WValueL) - switch setup.BRequest { - case usb.CLEAR_FEATURE: - ok = m.handleClearFeature(setup, wValue) - case usb.GET_MAX_LUN: - ok = m.handleGetMaxLun(setup, wValue) - case usb.MSC_RESET: - ok = m.handleReset(setup, wValue) - } - return ok -} - -// Handles the CLEAR_FEATURE request for clearing ENDPOINT_HALT/stall -func (m *msc) handleClearFeature(setup usb.Setup, wValue uint16) bool { - ok := false - // wValue is the feature selector (0x00 for ENDPOINT_HALT) - // We aren't handling any other feature selectors - // https://wiki.osdev.org/Universal_Serial_Bus#CLEAR_FEATURE - if wValue != 0 { - return ok - } - // Clearing the stall is not enough, continue stalling until a reset is received first - // 6.6.1 CBW Not Valid - // If the CBW is not valid, the device shall STALL the Bulk-In pipe. Also, the device - // shall either STALL the Bulk-Out pipe, or the device shall accept and discard any - // Bulk-Out data. The device shall maintain this state until a Reset Recovery - // For Reset Recovery the host shall issue in the following order: : - // (a) a Bulk-Only Mass Storage Reset (handleReset()) - // (b) a Clear Feature HALT to the Bulk-In endpoint (clear stall IN) - // (c) a Clear Feature HALT to the Bulk-Out endpoint (clear stall OUT) - // https://usb.org/sites/default/files/usbmassbulk_10.pdf - if m.state == mscStateNeedReset { - wIndex := setup.WIndex & 0x7F // Clear the direction bit from the endpoint address for comparison - if wIndex == usb.MSC_ENDPOINT_IN { - m.stallEndpoint(usb.MSC_ENDPOINT_IN) - } else if wIndex == usb.MSC_ENDPOINT_OUT { - m.stallEndpoint(usb.MSC_ENDPOINT_OUT) - } - return ok - } - - // Clear the direction bit from the endpoint address for comparison - wIndex := setup.WIndex & 0x7F - - // Clear the IN/OUT stalls if addressed to the endpoint, or both if addressed to the interface - if wIndex == usb.MSC_ENDPOINT_IN || wIndex == mscInterface { - m.clearStallEndpoint(usb.MSC_ENDPOINT_IN) - ok = true - } - if wIndex == usb.MSC_ENDPOINT_OUT || wIndex == mscInterface { - m.clearStallEndpoint(usb.MSC_ENDPOINT_OUT) - ok = true - } - // Send a CSW if needed to resume after the IN endpoint stall is cleared - if m.state == mscStateStatus && wIndex == usb.MSC_ENDPOINT_IN { - m.sendCSW(csw.StatusPassed) - ok = true - } - - if ok { - machine.SendZlp() - } - return ok -} - -// 3.2 Get Max LUN -// https://usb.org/sites/default/files/usbmassbulk_10.pdf -func (m *msc) handleGetMaxLun(setup usb.Setup, wValue uint16) bool { - if setup.WIndex != mscInterface || setup.WLength != 1 || wValue != 0 { - return false - } - // Send the maximum LUN ID number (zero-indexed, so n-1) supported by the device - m.resetBuffer(1) // Shrink buffer to 1 byte - m.buf[0] = m.maxLUN - return machine.SendUSBInPacket(usb.CONTROL_ENDPOINT, m.buf) -} - -// 3.1 Bulk-Only Mass Storage Reset -// https://usb.org/sites/default/files/usbmassbulk_10.pdf -func (m *msc) handleReset(setup usb.Setup, wValue uint16) bool { - if setup.WIndex != mscInterface || setup.WLength != 0 || wValue != 0 { - return false - } - // Reset to command waiting state - m.state = mscStateCmd - - // Reset transfer state - m.resetBuffer(0) - m.senseKey = 0 - m.addlSenseCode = 0 - m.addlSenseQualifier = 0 - - // Send a zero-length packet (ZLP) to indicate the reset is complete - machine.SendZlp() - - // Return true to indicate successful reset - return true -} - -func (m *msc) stallEndpoint(ep uint8) { - if ep == usb.MSC_ENDPOINT_IN { - m.txStalled = true - machine.USBDev.SetStallEPIn(usb.MSC_ENDPOINT_IN) - } else if ep == usb.MSC_ENDPOINT_OUT { - m.rxStalled = true - machine.USBDev.SetStallEPOut(usb.MSC_ENDPOINT_OUT) - } else if ep == usb.CONTROL_ENDPOINT { - machine.USBDev.SetStallEPIn(usb.CONTROL_ENDPOINT) - } -} - -func (m *msc) clearStallEndpoint(ep uint8) { - if ep == usb.MSC_ENDPOINT_IN { - machine.USBDev.ClearStallEPIn(usb.MSC_ENDPOINT_IN) - m.txStalled = false - } else if ep == usb.MSC_ENDPOINT_OUT { - machine.USBDev.ClearStallEPOut(usb.MSC_ENDPOINT_OUT) - m.rxStalled = false - } -} - -func (m *msc) setStringField(field []byte, value string) { - copy(field, []byte(value)) - for i := len(value); i < len(field); i++ { - field[i] = 0x20 // Fill remaining bytes with spaces - } -} - -func (m *msc) SetVendorID(vendorID string) { - m.setStringField(m.vendorID[:], vendorID) -} - -func (m *msc) SetProductID(productID string) { - m.setStringField(m.productID[:], productID) -} - -func (m *msc) SetProductRev(productRev string) { - m.setStringField(m.productRev[:], productRev) -} - -func SetVendorID(vendorID string) { - if MSC != nil { - MSC.SetVendorID(vendorID) - } -} -func SetProductID(productID string) { - if MSC != nil { - MSC.SetProductID(productID) - } -} -func SetProductRev(productRev string) { - if MSC != nil { - MSC.SetProductRev(productRev) - } -} diff --git a/emb/machine/_usb/usb.go b/emb/machine/_usb/usb.go deleted file mode 100644 index 40983a9..0000000 --- a/emb/machine/_usb/usb.go +++ /dev/null @@ -1,146 +0,0 @@ -package usb - -var ( - // TODO: allow setting these - STRING_LANGUAGE = [2]uint16{(3 << 8) | (2 + 2), 0x0409} // English -) - -const ( - DescriptorConfigCDC = 1 << iota - DescriptorConfigHID - DescriptorConfigMIDI - DescriptorConfigJoystick -) - -const ( - IMANUFACTURER = 1 - IPRODUCT = 2 - ISERIAL = 3 - - ENDPOINT_TYPE_DISABLE = 0xFF - ENDPOINT_TYPE_CONTROL = 0x00 - ENDPOINT_TYPE_ISOCHRONOUS = 0x01 - ENDPOINT_TYPE_BULK = 0x02 - ENDPOINT_TYPE_INTERRUPT = 0x03 - - EndpointOut = 0x00 - EndpointIn = 0x80 - - EndpointPacketSize = 64 // 64 for Full Speed, EPT size max is 1024 - - // bRequest - standard requests - GET_STATUS = 0 - CLEAR_FEATURE = 1 - SET_FEATURE = 3 - SET_ADDRESS = 5 - GET_DESCRIPTOR = 6 - SET_DESCRIPTOR = 7 - GET_CONFIGURATION = 8 - SET_CONFIGURATION = 9 - GET_INTERFACE = 10 - SET_INTERFACE = 11 - - // bRequest - HID class-specific requests - GET_REPORT = 1 - GET_IDLE = 2 - GET_PROTOCOL = 3 - SET_REPORT = 9 - SET_IDLE = 10 - SET_PROTOCOL = 11 - SET_REPORT_TYPE = 33 - - // bRequest - MSC class-specific requests - GET_MAX_LUN = 0xFE - MSC_RESET = 0xFF - - DEVICE_CLASS_COMMUNICATIONS = 0x02 - DEVICE_CLASS_HUMAN_INTERFACE = 0x03 - DEVICE_CLASS_STORAGE = 0x08 - DEVICE_CLASS_VENDOR_SPECIFIC = 0xFF - - CONFIG_POWERED_MASK = 0x40 - CONFIG_BUS_POWERED = 0x80 - CONFIG_SELF_POWERED = 0xC0 - CONFIG_REMOTE_WAKEUP = 0x20 - - // Interface - NumberOfInterfaces = 3 - CDC_ACM_INTERFACE = 0 // CDC ACM - CDC_DATA_INTERFACE = 1 // CDC Data - CDC_FIRST_ENDPOINT = 1 - HID_INTERFACE = 2 // HID - - // Endpoint - CONTROL_ENDPOINT = 0 - CDC_ENDPOINT_ACM = 1 - CDC_ENDPOINT_OUT = 2 - CDC_ENDPOINT_IN = 3 - HID_ENDPOINT_IN = 4 // for Interrupt In - HID_ENDPOINT_OUT = 5 // for Interrupt Out - MIDI_ENDPOINT_IN = 6 // for Bulk In - MIDI_ENDPOINT_OUT = 7 // for Bulk Out - MSC_ENDPOINT_IN = 6 // for Bulk In - MSC_ENDPOINT_OUT = 7 // for Bulk Out - - // bmRequestType - REQUEST_HOSTTODEVICE = 0x00 - REQUEST_DEVICETOHOST = 0x80 - REQUEST_DIRECTION = 0x80 - - REQUEST_STANDARD = 0x00 - REQUEST_CLASS = 0x20 - REQUEST_VENDOR = 0x40 - REQUEST_TYPE = 0x60 - - REQUEST_DEVICE = 0x00 - REQUEST_INTERFACE = 0x01 - REQUEST_ENDPOINT = 0x02 - REQUEST_OTHER = 0x03 - REQUEST_RECIPIENT = 0x1F - - REQUEST_DEVICETOHOST_CLASS_INTERFACE = (REQUEST_DEVICETOHOST | REQUEST_CLASS | REQUEST_INTERFACE) - REQUEST_HOSTTODEVICE_CLASS_INTERFACE = (REQUEST_HOSTTODEVICE | REQUEST_CLASS | REQUEST_INTERFACE) - REQUEST_DEVICETOHOST_STANDARD_INTERFACE = (REQUEST_DEVICETOHOST | REQUEST_STANDARD | REQUEST_INTERFACE) -) - -type Setup struct { - BmRequestType uint8 - BRequest uint8 - WValueL uint8 - WValueH uint8 - WIndex uint16 - WLength uint16 -} - -func NewSetup(data []byte) Setup { - u := Setup{} - u.BmRequestType = uint8(data[0]) - u.BRequest = uint8(data[1]) - u.WValueL = uint8(data[2]) - u.WValueH = uint8(data[3]) - u.WIndex = uint16(data[4]) | (uint16(data[5]) << 8) - u.WLength = uint16(data[6]) | (uint16(data[7]) << 8) - return u -} - -var ( - // VendorID aka VID is the officially assigned vendor number - // for this USB device. Only set this if you know what you are doing, - // since changing it can make it difficult to reflash some devices. - VendorID uint16 - - // ProductID aka PID is the product number associated with the officially assigned - // vendor number for this USB device. Only set this if you know what you are doing, - // since changing it can make it difficult to reflash some devices. - ProductID uint16 - - // Manufacturer is the manufacturer name displayed for this USB device. - Manufacturer string - - // Product is the product name displayed for this USB device. - Product string - - // Serial is the serial value displayed for this USB device. Assign a value to - // transmit the serial to the host when requested. - Serial string -) diff --git a/emb/machine/adc.go b/emb/machine/adc.go deleted file mode 100644 index e4b0cb3..0000000 --- a/emb/machine/adc.go +++ /dev/null @@ -1,13 +0,0 @@ -package machine - -// Hardware abstraction layer for the analog-to-digital conversion (ADC) -// peripheral. - -// ADCConfig holds ADC configuration parameters. If left unspecified, the zero -// value of each parameter will use the peripheral's default settings. -type ADCConfig struct { - Reference uint32 // analog reference voltage (AREF) in millivolts - Resolution uint32 // number of bits for a single conversion (e.g., 8, 10, 12) - Samples uint32 // number of samples for a single conversion (e.g., 4, 8, 16, 32) - SampleTime uint32 // sample time, in microseconds (µs) -} diff --git a/emb/machine/board_adafruit-esp32-feather-v2.go b/emb/machine/board_adafruit-esp32-feather-v2.go deleted file mode 100644 index f971dca..0000000 --- a/emb/machine/board_adafruit-esp32-feather-v2.go +++ /dev/null @@ -1,125 +0,0 @@ -//go:build adafruit_esp32_feather_v2 - -package machine - -const GPIO20 Pin = 20 - -const ( - IO0 = GPIO0 - IO2 = GPIO2 - IO4 = GPIO4 - IO5 = GPIO5 - IO7 = GPIO7 - IO8 = GPIO8 - IO12 = GPIO12 - IO13 = GPIO13 - IO14 = GPIO14 - IO15 = GPIO15 - IO19 = GPIO19 - IO20 = GPIO20 - IO21 = GPIO21 - IO22 = GPIO22 - IO25 = GPIO25 - IO26 = GPIO26 - IO27 = GPIO27 - IO32 = GPIO32 - IO33 = GPIO33 - IO34 = GPIO34 - IO35 = GPIO35 - IO36 = GPIO36 - IO37 = GPIO37 - IO38 = GPIO38 - IO39 = GPIO39 -) - -// Digital pins -const ( - D12 = IO12 - D13 = IO13 - D14 = IO14 - D15 = IO15 - D27 = IO27 - D32 = IO32 - D33 = IO33 - D37 = IO37 -) - -// Analog pins -const ( - A0 = IO26 - A1 = IO25 - A2 = IO34 - A3 = IO39 - A4 = IO36 - A5 = IO4 -) - -// Built-in LEDs and Button -const ( - WS2812 = IO0 - NEOPIXEL = WS2812 - NEOPIXEL_I2C_POWER = IO2 - LED = IO13 - BUTTON = IO38 -) - -// SPI pins -const ( - SPI_SCK_PIN = IO5 - SPI_MOSI_PIN = IO19 - SPI_MISO_PIN = IO21 - - SPI_SDO_PIN = SPI_MOSI_PIN - SPI_SDI_PIN = SPI_MISO_PIN - - // Silk labels - SCK = SPI_SCK_PIN - MO = SPI_MOSI_PIN - MI = SPI_MISO_PIN -) - -// I2C pins -const ( - I2C_SCL_PIN = IO20 - I2C_SDA_PIN = IO22 - - // Silk labels - SCL = I2C_SCL_PIN - SDA = I2C_SDA_PIN -) - -// ADC pins -const ( - ADC1_0 = IO36 - ADC1_1 = IO37 - ADC1_2 = IO38 - ADC1_3 = IO39 - ADC1_4 = IO32 - ADC1_5 = IO33 - ADC1_6 = IO34 - ADC1_7 = IO35 - - ADC2_0 = IO4 - ADC2_1 = IO0 - ADC2_2 = IO2 - ADC2_3 = IO15 - ADC2_4 = IO13 - ADC2_5 = IO12 - ADC2_6 = IO14 - ADC2_7 = IO27 - ADC2_8 = IO25 - ADC2_9 = IO26 -) - -// UART pins -const ( - UART_TX_PIN = IO19 - UART_RX_PIN = IO22 - - UART2_TX_PIN = IO8 - UART2_RX_PIN = IO7 - - // Silk labels - RX = UART2_RX_PIN - TX = UART2_TX_PIN -) diff --git a/emb/machine/board_ae_rp2040.go b/emb/machine/board_ae_rp2040.go deleted file mode 100644 index 716cf72..0000000 --- a/emb/machine/board_ae_rp2040.go +++ /dev/null @@ -1,86 +0,0 @@ -//go:build ae_rp2040 - -package machine - -// GPIO pins -const ( - GP0 Pin = GPIO0 - GP1 Pin = GPIO1 - GP2 Pin = GPIO2 - GP3 Pin = GPIO3 - GP4 Pin = GPIO4 - GP5 Pin = GPIO5 - GP6 Pin = GPIO6 - GP7 Pin = GPIO7 - GP8 Pin = GPIO8 - GP9 Pin = GPIO9 - GP10 Pin = GPIO10 - GP11 Pin = GPIO11 - GP12 Pin = GPIO12 - GP13 Pin = GPIO13 - GP14 Pin = GPIO14 - GP15 Pin = GPIO15 - GP16 Pin = GPIO16 - GP17 Pin = GPIO17 - GP18 Pin = GPIO18 - GP19 Pin = GPIO19 - GP20 Pin = GPIO20 - GP21 Pin = GPIO21 - GP22 Pin = GPIO22 - GP26 Pin = GPIO26 - GP27 Pin = GPIO27 - GP28 Pin = GPIO28 - GP29 Pin = GPIO29 - - // Onboard crystal oscillator frequency, in MHz. - xoscFreq = 12 // MHz -) - -// I2C Default pins on Raspberry Pico. -const ( - I2C0_SDA_PIN = GP4 - I2C0_SCL_PIN = GP5 - - I2C1_SDA_PIN = GP2 - I2C1_SCL_PIN = GP3 -) - -// SPI default pins -const ( - // Default Serial Clock Bus 0 for SPI communications - SPI0_SCK_PIN = GPIO18 - // Default Serial Out Bus 0 for SPI communications - SPI0_SDO_PIN = GPIO19 // Tx - // Default Serial In Bus 0 for SPI communications - SPI0_SDI_PIN = GPIO16 // Rx - - // Default Serial Clock Bus 1 for SPI communications - SPI1_SCK_PIN = GPIO10 - // Default Serial Out Bus 1 for SPI communications - SPI1_SDO_PIN = GPIO11 // Tx - // Default Serial In Bus 1 for SPI communications - SPI1_SDI_PIN = GPIO12 // Rx -) - -// UART pins -const ( - UART0_TX_PIN = GPIO0 - UART0_RX_PIN = GPIO1 - UART1_TX_PIN = GPIO8 - UART1_RX_PIN = GPIO9 - UART_TX_PIN = UART0_TX_PIN - UART_RX_PIN = UART0_RX_PIN -) - -var DefaultUART = UART0 - -// USB identifiers -const ( - usb_STRING_PRODUCT = "AE-RP2040" - usb_STRING_MANUFACTURER = "AKIZUKI DENSHI" -) - -var ( - usb_VID uint16 = 0x2E8A - usb_PID uint16 = 0x000A -) diff --git a/emb/machine/board_arduino.go b/emb/machine/board_arduino.go deleted file mode 100644 index a66889a..0000000 --- a/emb/machine/board_arduino.go +++ /dev/null @@ -1,40 +0,0 @@ -//go:build arduino - -package machine - -// Digital pins, marked as plain numbers on the board. -const ( - D0 = PD0 // RX - D1 = PD1 // TX - D2 = PD2 - D3 = PD3 - D4 = PD4 - D5 = PD5 - D6 = PD6 - D7 = PD7 - D8 = PB0 - D9 = PB1 - D10 = PB2 - D11 = PB3 - D12 = PB4 - D13 = PB5 -) - -// LED on the Arduino -const LED Pin = D13 - -// ADC on the Arduino -const ( - ADC0 Pin = PC0 - ADC1 Pin = PC1 - ADC2 Pin = PC2 - ADC3 Pin = PC3 - ADC4 Pin = PC4 // Used by TWI for SDA - ADC5 Pin = PC5 // Used by TWI for SCL -) - -// UART pins -const ( - UART_TX_PIN Pin = PD1 - UART_RX_PIN Pin = PD0 -) diff --git a/emb/machine/board_arduino_leonardo.go b/emb/machine/board_arduino_leonardo.go deleted file mode 100644 index 01f9570..0000000 --- a/emb/machine/board_arduino_leonardo.go +++ /dev/null @@ -1,39 +0,0 @@ -//go:build arduino_leonardo - -package machine - -// Return the current CPU frequency in hertz. -func CPUFrequency() uint32 { - return 16000000 -} - -// Digital pins, marked as plain numbers on the board. -const ( - D0 = PD2 // RX - D1 = PD3 // TX - D2 = PD1 - D3 = PD0 - D4 = PD4 - D5 = PC6 - D6 = PD7 - D7 = PE6 - D8 = PB4 - D9 = PB5 - D10 = PB6 - D11 = PB7 - D12 = PD6 - D13 = PC7 -) - -// LED on the Arduino -const LED Pin = D13 - -// ADC on the Arduino -const ( - ADC0 Pin = PF7 - ADC1 Pin = PF6 - ADC2 Pin = PF5 - ADC3 Pin = PF4 - ADC4 Pin = PF1 - ADC5 Pin = PF0 -) diff --git a/emb/machine/board_arduino_mega1280.go b/emb/machine/board_arduino_mega1280.go deleted file mode 100644 index 7bf6090..0000000 --- a/emb/machine/board_arduino_mega1280.go +++ /dev/null @@ -1,104 +0,0 @@ -//go:build arduino_mega1280 - -package machine - -// Return the current CPU frequency in hertz. -func CPUFrequency() uint32 { - return 16000000 -} - -const ( - A0 Pin = PF0 - A1 Pin = PF1 - A2 Pin = PF2 - A3 Pin = PF3 - A4 Pin = PF4 - A5 Pin = PF5 - A6 Pin = PF6 - A7 Pin = PF7 - A8 Pin = PK0 - A9 Pin = PK1 - A10 Pin = PK2 - A11 Pin = PK3 - A12 Pin = PK4 - A13 Pin = PK5 - A14 Pin = PK6 - A15 Pin = PK7 - - // Analog Input - ADC0 Pin = PF0 - ADC1 Pin = PF1 - ADC2 Pin = PF2 - ADC3 Pin = PF3 - ADC4 Pin = PF4 - ADC5 Pin = PF5 - ADC6 Pin = PF6 - ADC7 Pin = PF7 - ADC8 Pin = PK0 - ADC9 Pin = PK1 - ADC10 Pin = PK2 - ADC11 Pin = PK3 - ADC12 Pin = PK4 - ADC13 Pin = PK5 - ADC14 Pin = PK6 - ADC15 Pin = PK7 - - // Digital pins - D0 Pin = PE0 - D1 Pin = PE1 - D2 Pin = PE4 - D3 Pin = PE5 - D4 Pin = PG5 - D5 Pin = PE3 - D6 Pin = PH3 - D7 Pin = PH4 - D8 Pin = PH5 - D9 Pin = PH6 - D10 Pin = PB4 - D11 Pin = PB5 - D12 Pin = PB6 - D13 Pin = PB7 - D14 Pin = PJ1 - D15 Pin = PJ0 - D16 Pin = PH1 - D17 Pin = PH0 - D18 Pin = PD3 - D19 Pin = PD2 - D20 Pin = PD1 - D21 Pin = PD0 - D22 Pin = PA0 - D23 Pin = PA1 - D24 Pin = PA2 - D25 Pin = PA3 - D26 Pin = PA4 - D27 Pin = PA5 - D28 Pin = PA6 - D29 Pin = PA7 - D30 Pin = PC7 - D31 Pin = PC6 - D32 Pin = PC5 - D33 Pin = PC4 - D34 Pin = PC3 - D35 Pin = PC2 - D36 Pin = PC1 - D37 Pin = PC0 - D38 Pin = PD7 - D39 Pin = PG2 - D40 Pin = PG1 - D41 Pin = PG0 - D42 Pin = PL7 - D43 Pin = PL6 - D44 Pin = PL5 - D45 Pin = PL4 - D46 Pin = PL3 - D47 Pin = PL2 - D48 Pin = PL1 - D49 Pin = PL0 - D50 Pin = PB3 - D51 Pin = PB2 - D52 Pin = PB1 - D53 Pin = PB0 - - AREF Pin = NoPin - LED Pin = PB7 -) diff --git a/emb/machine/board_arduino_mega2560.go b/emb/machine/board_arduino_mega2560.go deleted file mode 100644 index 2e4aefd..0000000 --- a/emb/machine/board_arduino_mega2560.go +++ /dev/null @@ -1,165 +0,0 @@ -//go:build arduino_mega2560 - -package machine - -import ( - "device/avr" - "runtime/interrupt" -) - -// Return the current CPU frequency in hertz. -func CPUFrequency() uint32 { - return 16000000 -} - -const ( - A0 Pin = PF0 - A1 Pin = PF1 - A2 Pin = PF2 - A3 Pin = PF3 - A4 Pin = PF4 - A5 Pin = PF5 - A6 Pin = PF6 - A7 Pin = PF7 - A8 Pin = PK0 - A9 Pin = PK1 - A10 Pin = PK2 - A11 Pin = PK3 - A12 Pin = PK4 - A13 Pin = PK5 - A14 Pin = PK6 - A15 Pin = PK7 - - // Analog Input - ADC0 Pin = PF0 - ADC1 Pin = PF1 - ADC2 Pin = PF2 - ADC3 Pin = PF3 - ADC4 Pin = PF4 - ADC5 Pin = PF5 - ADC6 Pin = PF6 - ADC7 Pin = PF7 - ADC8 Pin = PK0 - ADC9 Pin = PK1 - ADC10 Pin = PK2 - ADC11 Pin = PK3 - ADC12 Pin = PK4 - ADC13 Pin = PK5 - ADC14 Pin = PK6 - ADC15 Pin = PK7 - - // Digital pins - D0 Pin = PE0 - D1 Pin = PE1 - D2 Pin = PE4 - D3 Pin = PE5 - D4 Pin = PG5 - D5 Pin = PE3 - D6 Pin = PH3 - D7 Pin = PH4 - D8 Pin = PH5 - D9 Pin = PH6 - D10 Pin = PB4 - D11 Pin = PB5 - D12 Pin = PB6 - D13 Pin = PB7 - D14 Pin = PJ1 // TX3 - D15 Pin = PJ0 // RX3 - D16 Pin = PH1 // TX2 - D17 Pin = PH0 // RX2 - D18 Pin = PD3 // TX1 - D19 Pin = PD2 // RX1 - D20 Pin = PD1 - D21 Pin = PD0 - D22 Pin = PA0 - D23 Pin = PA1 - D24 Pin = PA2 - D25 Pin = PA3 - D26 Pin = PA4 - D27 Pin = PA5 - D28 Pin = PA6 - D29 Pin = PA7 - D30 Pin = PC7 - D31 Pin = PC6 - D32 Pin = PC5 - D33 Pin = PC4 - D34 Pin = PC3 - D35 Pin = PC2 - D36 Pin = PC1 - D37 Pin = PC0 - D38 Pin = PD7 - D39 Pin = PG2 - D40 Pin = PG1 - D41 Pin = PG0 - D42 Pin = PL7 - D43 Pin = PL6 - D44 Pin = PL5 - D45 Pin = PL4 - D46 Pin = PL3 - D47 Pin = PL2 - D48 Pin = PL1 - D49 Pin = PL0 - D50 Pin = PB3 - D51 Pin = PB2 - D52 Pin = PB1 - D53 Pin = PB0 - - AREF Pin = NoPin - LED Pin = PB7 -) - -// UART pins -const ( - UART_TX_PIN Pin = UART0_TX_PIN - UART_RX_PIN Pin = UART0_RX_PIN - UART0_TX_PIN Pin = D1 - UART0_RX_PIN Pin = D0 - UART1_TX_PIN Pin = D18 - UART1_RX_PIN Pin = D19 - UART2_TX_PIN Pin = D16 - UART2_RX_PIN Pin = D17 - UART3_TX_PIN Pin = D14 - UART3_RX_PIN Pin = D15 -) - -var ( - UART1 = &_UART1 - _UART1 = UART{ - Buffer: NewRingBuffer(), - - dataReg: avr.UDR1, - baudRegH: avr.UBRR1H, - baudRegL: avr.UBRR1L, - statusRegA: avr.UCSR1A, - statusRegB: avr.UCSR1B, - statusRegC: avr.UCSR1C, - } - UART2 = &_UART2 - _UART2 = UART{ - Buffer: NewRingBuffer(), - - dataReg: avr.UDR2, - baudRegH: avr.UBRR2H, - baudRegL: avr.UBRR2L, - statusRegA: avr.UCSR2A, - statusRegB: avr.UCSR2B, - statusRegC: avr.UCSR2C, - } - UART3 = &_UART3 - _UART3 = UART{ - Buffer: NewRingBuffer(), - - dataReg: avr.UDR3, - baudRegH: avr.UBRR3H, - baudRegL: avr.UBRR3L, - statusRegA: avr.UCSR3A, - statusRegB: avr.UCSR3B, - statusRegC: avr.UCSR3C, - } -) - -func init() { - interrupt.New(irq_USART1_RX, _UART1.handleInterrupt) - interrupt.New(irq_USART2_RX, _UART2.handleInterrupt) - interrupt.New(irq_USART3_RX, _UART3.handleInterrupt) -} diff --git a/emb/machine/board_arduino_mkr1000.go b/emb/machine/board_arduino_mkr1000.go deleted file mode 100644 index f513012..0000000 --- a/emb/machine/board_arduino_mkr1000.go +++ /dev/null @@ -1,91 +0,0 @@ -//go:build arduino_mkr1000 - -// This contains the pin mappings for the Arduino MKR1000 board. -// -// For more information, see: https://store.arduino.cc/usa/arduino-mkr1000-with-headers-mounted -package machine - -// used to reset into bootloader -const resetMagicValue = 0x07738135 - -// GPIO Pins -const ( - D0 Pin = PA22 // PWM available - D1 Pin = PA23 // PWM available - D2 Pin = PA10 // PWM available - D3 Pin = PA11 // PWM available - D4 Pin = PB10 // PWM available - D5 Pin = PB11 // PWM available - - D6 Pin = PA20 // PWM available - D7 Pin = PA21 // PWM available - D8 Pin = PA16 // PWM available - D9 Pin = PA17 - D10 Pin = PA19 // PWM available - D11 Pin = PA08 // SDA - D12 Pin = PA09 // PWM available, SCL - D13 Pin = PB23 // RX - D14 Pin = PB22 // TX - - RX0 Pin = PB23 // UART2 RX - TX1 Pin = PB22 // UART2 TX -) - -// Analog pins -const ( - A0 Pin = PA02 // ADC0/AIN[0] - A1 Pin = PB02 // AIN[10] - A2 Pin = PB03 // AIN[11] - A3 Pin = PA04 // AIN[04] - A4 Pin = PA05 // AIN[05] - A5 Pin = PA06 // AIN[06] - A6 Pin = PA07 // AIN[07] -) - -const ( - LED = D6 -) - -// USBCDC pins -const ( - USBCDC_DM_PIN Pin = PA24 - USBCDC_DP_PIN Pin = PA25 -) - -// UART1 pins -const ( - UART_TX_PIN Pin = PB22 - UART_RX_PIN Pin = PB23 -) - -// I2C pins -const ( - SDA_PIN Pin = D11 // SDA - SCL_PIN Pin = D12 // SCL -) - -// SPI pins -const ( - SPI0_SCK_PIN Pin = D9 // SCK: S1 - SPI0_SDO_PIN Pin = D8 // SDO: S1 - SPI0_SDI_PIN Pin = D10 // SDI: S1 -) - -// I2S pins -const ( - I2S_SCK_PIN Pin = PA10 - I2S_SDO_PIN Pin = PA07 - I2S_SDI_PIN = NoPin - I2S_WS_PIN = NoPin // TODO: figure out what this is on Arduino MKR1000 -) - -// USB CDC identifiers -const ( - usb_STRING_PRODUCT = "Arduino MKR1000" - usb_STRING_MANUFACTURER = "Arduino" -) - -var ( - usb_VID uint16 = 0x2341 - usb_PID uint16 = 0x804e -) diff --git a/emb/machine/board_arduino_mkrwifi1010.go b/emb/machine/board_arduino_mkrwifi1010.go deleted file mode 100644 index c68da9b..0000000 --- a/emb/machine/board_arduino_mkrwifi1010.go +++ /dev/null @@ -1,124 +0,0 @@ -//go:build arduino_mkrwifi1010 - -// This contains the pin mappings for the Arduino MKR WiFi 1010 board. -// -// For more information, see: https://store.arduino.cc/usa/mkr-wifi-1010 -package machine - -// used to reset into bootloader -const resetMagicValue = 0x07738135 - -// GPIO Pins -const ( - D0 Pin = PA22 // PWM available - D1 Pin = PA23 // PWM available - D2 Pin = PA10 // PWM available - D3 Pin = PA11 // PWM available - D4 Pin = PB10 // PWM available - D5 Pin = PB11 // PWM available - - D6 Pin = PA20 // PWM available - D7 Pin = PA21 // PWM available - D8 Pin = PA16 // PWM available - D9 Pin = PA17 - D10 Pin = PA19 // PWM available - D11 Pin = PA08 // SDA - D12 Pin = PA09 // PWM available, SCL - D13 Pin = PB23 // RX - D14 Pin = PB22 // TX - - RX0 Pin = PB23 // UART1 RX - TX1 Pin = PB22 // UART1 TX -) - -// Analog pins -const ( - A0 Pin = PA02 // ADC0/AIN[0] - A1 Pin = PB02 // AIN[10] - A2 Pin = PB03 // AIN[11] - A3 Pin = PA04 // AIN[04] - A4 Pin = PA05 // AIN[05] - A5 Pin = PA06 // AIN[06] - A6 Pin = PA07 // AIN[07] -) - -const ( - LED = D6 -) - -// USBCDC pins -const ( - USBCDC_DM_PIN Pin = PA24 - USBCDC_DP_PIN Pin = PA25 -) - -// UART1 pins -const ( - UART_TX_PIN Pin = PB22 - UART_RX_PIN Pin = PB23 -) - -// I2C pins -const ( - SDA_PIN Pin = D11 // SDA - SCL_PIN Pin = D12 // SCL -) - -// SPI pins -const ( - SPI0_SCK_PIN Pin = D9 // SCK: S1 - SPI0_SDO_PIN Pin = D8 // SDO: S1 - SPI0_SDI_PIN Pin = D10 // SDI: S1 -) - -// I2S pins -const ( - I2S_SCK_PIN Pin = PA10 - I2S_SDO_PIN Pin = PA07 - I2S_SDI_PIN = NoPin - I2S_WS_PIN = NoPin // TODO: figure out what this is on Arduino MKR WiFi 1010. -) - -// NINA-W102 Pins -const ( - NINA_SDO Pin = PA12 - NINA_SDI Pin = PA13 - NINA_CS Pin = PA14 - NINA_SCK Pin = PA15 - NINA_GPIO0 Pin = PA27 - NINA_RESETN Pin = PB08 - NINA_ACK Pin = PA28 - NINA_TX Pin = PA22 - NINA_RX Pin = PA23 -) - -// UART on the Arduino MKR WiFi 1010. -var UART1 = &sercomUSART5 - -// I2C on the Arduino MKR WiFi 1010. -var ( - I2C0 = sercomI2CM2 -) - -// SPI on the Arduino MKR WiFi 1010. -var ( - SPI0 = sercomSPIM1 - - SPI1 = sercomSPIM4 - NINA_SPI = SPI1 -) - -// USB CDC identifiers -const ( - usb_STRING_PRODUCT = "Arduino MKR WiFi 1010" - usb_STRING_MANUFACTURER = "Arduino" -) - -var ( - usb_VID uint16 = 0x2341 - usb_PID uint16 = 0x8054 -) - -var ( - DefaultUART = UART1 -) diff --git a/emb/machine/board_arduino_nano.go b/emb/machine/board_arduino_nano.go deleted file mode 100644 index c677219..0000000 --- a/emb/machine/board_arduino_nano.go +++ /dev/null @@ -1,40 +0,0 @@ -//go:build arduino_nano - -package machine - -// Digital pins. -const ( - D0 = PD0 // RX0 - D1 = PD1 // TX1 - D2 = PD2 - D3 = PD3 - D4 = PD4 - D5 = PD5 - D6 = PD6 - D7 = PD7 - D8 = PB0 - D9 = PB1 - D10 = PB2 - D11 = PB3 - D12 = PB4 - D13 = PB5 -) - -// LED on the Arduino -const LED Pin = D13 - -// ADC on the Arduino -const ( - ADC0 Pin = PC0 - ADC1 Pin = PC1 - ADC2 Pin = PC2 - ADC3 Pin = PC3 - ADC4 Pin = PC4 // Used by TWI for SDA - ADC5 Pin = PC5 // Used by TWI for SCL -) - -// UART pins -const ( - UART_TX_PIN Pin = PD1 - UART_RX_PIN Pin = PD0 -) diff --git a/emb/machine/board_arduino_nano33.go b/emb/machine/board_arduino_nano33.go deleted file mode 100644 index 9232d38..0000000 --- a/emb/machine/board_arduino_nano33.go +++ /dev/null @@ -1,135 +0,0 @@ -//go:build arduino_nano33 - -// This contains the pin mappings for the Arduino Nano33 IoT board. -// -// For more information, see: https://store.arduino.cc/nano-33-iot -package machine - -// used to reset into bootloader -const resetMagicValue = 0x07738135 - -// GPIO Pins -const ( - RX0 Pin = PB23 // UART2 RX - TX1 Pin = PB22 // UART2 TX - - D2 Pin = PB10 // PWM available - D3 Pin = PB11 // PWM available - D4 Pin = PA07 - D5 Pin = PA05 // PWM available - D6 Pin = PA04 // PWM available - D7 Pin = PA06 - - D8 Pin = PA18 - D9 Pin = PA20 // PWM available - D10 Pin = PA21 // PWM available - D11 Pin = PA16 // PWM available - D12 Pin = PA19 // PWM available - - D13 Pin = PA17 -) - -// Analog pins -const ( - A0 Pin = PA02 // ADC/AIN[0] - A1 Pin = PB02 // ADC/AIN[10] - A2 Pin = PA11 // ADC/AIN[19] - A3 Pin = PA10 // ADC/AIN[18], - A4 Pin = PB08 // ADC/AIN[2], SCL: SERCOM2/PAD[1] - A5 Pin = PB09 // ADC/AIN[3], SDA: SERCOM2/PAD[1] - A6 Pin = PA09 // ADC/AIN[17] - A7 Pin = PB03 // ADC/AIN[11] -) - -const ( - LED = D13 -) - -// USBCDC pins -const ( - USBCDC_DM_PIN Pin = PA24 - USBCDC_DP_PIN Pin = PA25 -) - -// UART1 pins -const ( - UART_TX_PIN Pin = PA22 - UART_RX_PIN Pin = PA23 -) - -// UART1 on the Arduino Nano 33 connects to the onboard NINA-W102 WiFi chip. -var UART1 = &sercomUSART3 - -// UART2 on the Arduino Nano 33 connects to the normal TX/RX pins. -var UART2 = &sercomUSART5 - -// UART_NINA on the Arduino Nano 33 connects to the NINA HCI. -var UART_NINA = &sercomUSART2 - -// I2C pins -const ( - SDA_PIN Pin = A4 // SDA: SERCOM4/PAD[1] - SCL_PIN Pin = A5 // SCL: SERCOM4/PAD[1] -) - -// I2C on the Arduino Nano 33. -var ( - I2C0 = sercomI2CM4 -) - -// SPI pins -const ( - SPI0_SCK_PIN Pin = D13 // SCK: SERCOM1/PAD[1] - SPI0_SDO_PIN Pin = D11 // SDO: SERCOM1/PAD[0] - SPI0_SDI_PIN Pin = D12 // SDI: SERCOM1/PAD[3] -) - -// SPI on the Arduino Nano 33. -var SPI0 = sercomSPIM1 - -// SPI1 is connected to the NINA-W102 chip on the Arduino Nano 33. -var ( - SPI1 = sercomSPIM2 - NINA_SPI = SPI1 -) - -// NINA-W102 Pins -const ( - NINA_SDO Pin = PA12 - NINA_SDI Pin = PA13 - NINA_CS Pin = PA14 - NINA_SCK Pin = PA15 - NINA_GPIO0 Pin = PA27 - NINA_RESETN Pin = PA08 - NINA_ACK Pin = PA28 - NINA_TX Pin = PA12 - NINA_RX Pin = PA13 - NINA_RTS Pin = PA14 - NINA_CTS Pin = PA15 -) - -// NINA-W102 settings -const ( - NINA_BAUDRATE = 912600 - NINA_RESET_INVERTED = true - NINA_SOFT_FLOWCONTROL = false -) - -// I2S pins -const ( - I2S_SCK_PIN Pin = PA10 - I2S_SDO_PIN Pin = PA08 - I2S_SDI_PIN = NoPin - I2S_WS_PIN = NoPin // TODO: figure out what this is on Arduino Nano 33. -) - -// USB CDC identifiers -const ( - usb_STRING_PRODUCT = "Arduino NANO 33 IoT" - usb_STRING_MANUFACTURER = "Arduino" -) - -var ( - usb_VID uint16 = 0x2341 - usb_PID uint16 = 0x8057 -) diff --git a/emb/machine/board_arduino_zero.go b/emb/machine/board_arduino_zero.go deleted file mode 100644 index 758fcb1..0000000 --- a/emb/machine/board_arduino_zero.go +++ /dev/null @@ -1,102 +0,0 @@ -//go:build sam && atsamd21 && arduino_zero - -package machine - -// used to reset into bootloader -const resetMagicValue = 0x07738135 - -// GPIO Pins - Digital Low -const ( - D0 = PA11 // RX - D1 = PA10 // TX - D2 = PA14 - D3 = PA09 // PWM available - D4 = PA08 // PWM available - D5 = PA15 // PWM available - D6 = PA20 // PWM available - D7 = PA21 -) - -// GPIO Pins - Digital High -const ( - D8 = PA06 // PWM available - D9 = PA07 // PWM available - D10 = PA18 // PWM available - D11 = PA16 // PWM available - D12 = PA19 // PWM available - D13 = PA17 // PWM available -) - -// ADC pins -const ( - AREF Pin = PA03 - ADC0 Pin = PA02 - ADC1 Pin = PB08 - ADC2 Pin = PB09 - ADC3 Pin = PA04 - ADC4 Pin = PA05 - ADC5 Pin = PB02 -) - -// LEDs on the Arduino Zero -const ( - LED = LED1 - LED1 Pin = D13 - LED2 Pin = PA27 // TX LED - LED3 Pin = PB03 // RX LED -) - -// SPI pins - EDBG connected -const ( - SPI0_SDO_PIN Pin = PA16 // MOSI: SERCOM1/PAD[0] - SPI0_SDI_PIN Pin = PA19 // MISO: SERCOM1/PAD[2] - SPI0_SCK_PIN Pin = PA17 // SCK: SERCOM1/PAD[3] -) - -// SPI pins (Legacy ICSP) -const ( - SPI1_SDO_PIN Pin = PB10 // MOSI: SERCOM4/PAD[2] - Pin 4 - SPI1_SDI_PIN Pin = PA12 // MISO: SERCOM4/PAD[0] - Pin 1 - SPI1_SCK_PIN Pin = PB11 // SCK: SERCOM4/PAD[3] - Pin 3 -) - -// I2C pins - EDBG connected -const ( - SDA_PIN Pin = PA22 // SDA: SERCOM3/PAD[0] - Pin 20 - SCL_PIN Pin = PA23 // SCL: SERCOM3/PAD[1] - Pin 21 -) - -// I2S pins - might not be exposed -const ( - I2S_SCK_PIN Pin = PA10 - I2S_SDO_PIN Pin = PA07 - I2S_SDI_PIN = NoPin - I2S_WS_PIN Pin = PA11 -) - -// UART0 pins - EDBG connected -const ( - UART_RX_PIN Pin = D0 - UART_TX_PIN Pin = D1 -) - -// 'native' USB port pins -const ( - USBCDC_DM_PIN Pin = PA24 - USBCDC_DP_PIN Pin = PA25 -) - -// USB CDC identifiers -const ( - usb_STRING_PRODUCT = "Arduino Zero" - usb_STRING_MANUFACTURER = "Arduino LLC" - - usb_VID uint16 = 0x2341 - usb_PID uint16 = 0x804d -) - -// 32.768 KHz Crystal -const ( - XIN32 Pin = PA00 - XOUT32 Pin = PA01 -) diff --git a/emb/machine/board_atmega328p.go b/emb/machine/board_atmega328p.go deleted file mode 100644 index 234bf31..0000000 --- a/emb/machine/board_atmega328p.go +++ /dev/null @@ -1,42 +0,0 @@ -//go:build (avr && atmega328p) || arduino || arduino_nano - -package machine - -// Return the current CPU frequency in hertz. -func CPUFrequency() uint32 { - return 16000000 -} - -const ( - // Note: start at port B because there is no port A. - portB Pin = iota * 8 - portC - portD -) - -const ( - PB0 = portB + 0 - PB1 = portB + 1 // peripherals: Timer1 channel A - PB2 = portB + 2 // peripherals: Timer1 channel B - PB3 = portB + 3 // peripherals: Timer2 channel A - PB4 = portB + 4 - PB5 = portB + 5 - PB6 = portB + 6 - PB7 = portB + 7 - PC0 = portC + 0 - PC1 = portC + 1 - PC2 = portC + 2 - PC3 = portC + 3 - PC4 = portC + 4 - PC5 = portC + 5 - PC6 = portC + 6 - PC7 = portC + 7 - PD0 = portD + 0 - PD1 = portD + 1 - PD2 = portD + 2 - PD3 = portD + 3 // peripherals: Timer2 channel B - PD4 = portD + 4 - PD5 = portD + 5 // peripherals: Timer0 channel B - PD6 = portD + 6 // peripherals: Timer0 channel A - PD7 = portD + 7 -) diff --git a/emb/machine/board_atmega328pb.go b/emb/machine/board_atmega328pb.go deleted file mode 100644 index e3e45f0..0000000 --- a/emb/machine/board_atmega328pb.go +++ /dev/null @@ -1,51 +0,0 @@ -//go:build avr && atmega328pb - -package machine - -// Return the current CPU frequency in hertz. -func CPUFrequency() uint32 { - return 16000000 -} - -const ( - // Note: start at port B because there is no port A. - portB Pin = iota * 8 - portC - portD - portE -) - -const ( - PB0 = portB + 0 - PB1 = portB + 1 // peripherals: Timer1 channel A - PB2 = portB + 2 // peripherals: Timer1 channel B - PB3 = portB + 3 // peripherals: Timer2 channel A - PB4 = portB + 4 - PB5 = portB + 5 - PB6 = portB + 6 - PB7 = portB + 7 - PC0 = portC + 0 - PC1 = portC + 1 - PC2 = portC + 2 - PC3 = portC + 3 - PC4 = portC + 4 - PC5 = portC + 5 - PC6 = portC + 6 - PC7 = portC + 7 - PD0 = portD + 0 - PD1 = portD + 1 - PD2 = portD + 2 - PD3 = portD + 3 // peripherals: Timer2 channel B - PD4 = portD + 4 - PD5 = portD + 5 // peripherals: Timer0 channel B - PD6 = portD + 6 // peripherals: Timer0 channel A - PD7 = portD + 7 - PE0 = portE + 0 - PE1 = portE + 1 - PE2 = portE + 2 - PE3 = portE + 3 - PE4 = portE + 4 - PE5 = portE + 5 - PE6 = portE + 6 - PE7 = portE + 7 -) diff --git a/emb/machine/board_atsamd21.go b/emb/machine/board_atsamd21.go deleted file mode 100644 index 8782249..0000000 --- a/emb/machine/board_atsamd21.go +++ /dev/null @@ -1,76 +0,0 @@ -//go:build (sam && atsamd21) || arduino_nano33 || circuitplay_express - -package machine - -// Return the current CPU frequency in hertz. -func CPUFrequency() uint32 { - return 48000000 -} - -// Hardware pins -const ( - PA00 Pin = 0 // peripherals: TCC2 channel 0 - PA01 Pin = 1 // peripherals: TCC2 channel 1 - PA02 Pin = 2 - PA03 Pin = 3 - PA04 Pin = 4 // peripherals: TCC0 channel 0 - PA05 Pin = 5 // peripherals: TCC0 channel 1 - PA06 Pin = 6 // peripherals: TCC1 channel 0 - PA07 Pin = 7 // peripherals: TCC1 channel 1 - PA08 Pin = 8 // peripherals: TCC0 channel 0, TCC1 channel 2 - PA09 Pin = 9 // peripherals: TCC0 channel 1, TCC1 channel 3 - PA10 Pin = 10 // peripherals: TCC1 channel 0, TCC0 channel 2 - PA11 Pin = 11 // peripherals: TCC1 channel 1, TCC0 channel 3 - PA12 Pin = 12 // peripherals: TCC2 channel 0, TCC0 channel 2 - PA13 Pin = 13 // peripherals: TCC2 channel 1, TCC0 channel 3 - PA14 Pin = 14 // peripherals: TCC0 channel 0 - PA15 Pin = 15 // peripherals: TCC0 channel 1 - PA16 Pin = 16 // peripherals: TCC2 channel 0, TCC0 channel 2 - PA17 Pin = 17 // peripherals: TCC2 channel 1, TCC0 channel 3 - PA18 Pin = 18 // peripherals: TCC0 channel 2 - PA19 Pin = 19 // peripherals: TCC0 channel 3 - PA20 Pin = 20 // peripherals: TCC0 channel 2 - PA21 Pin = 21 // peripherals: TCC0 channel 3 - PA22 Pin = 22 // peripherals: TCC0 channel 0 - PA23 Pin = 23 // peripherals: TCC0 channel 1 - PA24 Pin = 24 // peripherals: TCC1 channel 2 - PA25 Pin = 25 // peripherals: TCC1 channel 3 - PA26 Pin = 26 - PA27 Pin = 27 - PA28 Pin = 28 - PA29 Pin = 29 - PA30 Pin = 30 // peripherals: TCC1 channel 0 - PA31 Pin = 31 // peripherals: TCC1 channel 1 - PB00 Pin = 32 - PB01 Pin = 33 - PB02 Pin = 34 - PB03 Pin = 35 - PB04 Pin = 36 - PB05 Pin = 37 - PB06 Pin = 38 - PB07 Pin = 39 - PB08 Pin = 40 - PB09 Pin = 41 - PB10 Pin = 42 // peripherals: TCC0 channel 0 - PB11 Pin = 43 // peripherals: TCC0 channel 1 - PB12 Pin = 44 // peripherals: TCC0 channel 2 - PB13 Pin = 45 // peripherals: TCC0 channel 3 - PB14 Pin = 46 - PB15 Pin = 47 - PB16 Pin = 48 // peripherals: TCC0 channel 0 - PB17 Pin = 49 // peripherals: TCC0 channel 1 - PB18 Pin = 50 - PB19 Pin = 51 - PB20 Pin = 52 - PB21 Pin = 53 - PB22 Pin = 54 - PB23 Pin = 55 - PB24 Pin = 56 - PB25 Pin = 57 - PB26 Pin = 58 - PB27 Pin = 59 - PB28 Pin = 60 - PB29 Pin = 61 - PB30 Pin = 62 // peripherals: TCC0 channel 0, TCC1 channel 2 - PB31 Pin = 63 // peripherals: TCC0 channel 1, TCC1 channel 3 -) diff --git a/emb/machine/board_atsame54-xpro.go b/emb/machine/board_atsame54-xpro.go deleted file mode 100644 index ae1086d..0000000 --- a/emb/machine/board_atsame54-xpro.go +++ /dev/null @@ -1,293 +0,0 @@ -//go:build atsame54_xpro - -package machine - -import ( - "device/sam" -) - -// Definition for compatibility, but not used -const resetMagicValue = 0x00000000 - -const ( - LED = PC18 - BUTTON = PB31 -) - -const ( - // https://ww1.microchip.com/downloads/en/DeviceDoc/70005321A.pdf - - // Extension Header EXT1 - EXT1_PIN3_ADC_P = PB04 - EXT1_PIN4_ADC_N = PB05 - EXT1_PIN5_GPIO1 = PA06 - EXT1_PIN6_GPIO2 = PA07 - EXT1_PIN7_PWM_P = PB08 - EXT1_PIN8_PWM_N = PB09 - EXT1_PIN9_IRQ = PB07 - EXT1_PIN9_GPIO = PB07 - EXT1_PIN10_SPI_SS_B = PA27 - EXT1_PIN10_GPIO = PA27 - EXT1_PIN11_TWI_SDA = PA22 - EXT1_PIN12_TWI_SCL = PA23 - EXT1_PIN13_UART_RX = PA05 - EXT1_PIN14_UART_TX = PA04 - EXT1_PIN15_SPI_SS_A = PB28 - EXT1_PIN16_SPI_SDO = PB27 - EXT1_PIN17_SPI_SDI = PB29 - EXT1_PIN18_SPI_SCK = PB26 - - // Extension Header EXT2 - EXT2_PIN3_ADC_P = PB00 - EXT2_PIN4_ADC_N = PA03 - EXT2_PIN5_GPIO1 = PB01 - EXT2_PIN6_GPIO2 = PB06 - EXT2_PIN7_PWM_P = PB14 - EXT2_PIN8_PWM_N = PB15 - EXT2_PIN9_IRQ = PD00 - EXT2_PIN9_GPIO = PD00 - EXT2_PIN10_SPI_SS_B = PB02 - EXT2_PIN10_GPIO = PB02 - EXT2_PIN11_TWI_SDA = PD08 - EXT2_PIN12_TWI_SCL = PD09 - EXT2_PIN13_UART_RX = PB17 - EXT2_PIN14_UART_TX = PB16 - EXT2_PIN15_SPI_SS_A = PC06 - EXT2_PIN16_SPI_SDO = PC04 - EXT2_PIN17_SPI_SDI = PC07 - EXT2_PIN18_SPI_SCK = PC05 - - // Extension Header EXT3 - EXT3_PIN3_ADC_P = PC02 - EXT3_PIN4_ADC_N = PC03 - EXT3_PIN5_GPIO1 = PC01 - EXT3_PIN6_GPIO2 = PC10 - EXT3_PIN7_PWM_P = PD10 - EXT3_PIN8_PWM_N = PD11 - EXT3_PIN9_IRQ = PC30 - EXT3_PIN9_GPIO = PC30 - EXT3_PIN10_SPI_SS_B = PC31 - EXT3_PIN10_GPIO = PC31 - EXT3_PIN11_TWI_SDA = PD08 - EXT3_PIN12_TWI_SCL = PD09 - EXT3_PIN13_UART_RX = PC23 - EXT3_PIN14_UART_TX = PC22 - EXT3_PIN15_SPI_SS_A = PC14 - EXT3_PIN16_SPI_SDO = PC04 - EXT3_PIN17_SPI_SDI = PC07 - EXT3_PIN18_SPI_SCK = PC05 - - // SD_CARD - SD_CARD_MCDA0 = PB18 - SD_CARD_MCDA1 = PB19 - SD_CARD_MCDA2 = PB20 - SD_CARD_MCDA3 = PB21 - SD_CARD_MCCK = PA21 - SD_CARD_MCCDA = PA20 - SD_CARD_DETECT = PD20 - SD_CARD_PROTECT = PD21 - - // I2C - I2C_SDA = PD08 - I2C_SCL = PD09 - - // CAN - CAN0_TX = PA22 - CAN0_RX = PA23 - - CAN1_STANDBY = PC13 - CAN1_TX = PB12 - CAN1_RX = PB13 - - CAN_STANDBY = CAN1_STANDBY - CAN_TX = CAN1_TX - CAN_RX = CAN1_RX - - // PDEC - PDEC_PHASE_A = PC16 - PDEC_PHASE_B = PC17 - PDEC_INDEX = PC18 - - // PCC - PCC_I2C_SDA = PD08 - PCC_I2C_SCL = PD09 - PCC_VSYNC_DEN1 = PA12 - PCC_HSYNC_DEN2 = PA13 - PCC_CLK = PA14 - PCC_XCLK = PA15 - PCC_DATA00 = PA16 - PCC_DATA01 = PA17 - PCC_DATA02 = PA18 - PCC_DATA03 = PA19 - PCC_DATA04 = PA20 - PCC_DATA05 = PA21 - PCC_DATA06 = PA22 - PCC_DATA07 = PA23 - PCC_DATA08 = PB14 - PCC_DATA09 = PB15 - PCC_RESET = PC12 - PCC_PWDN = PC11 - - // Ethernet - ETHERNET_TXCK = PA14 - ETHERNET_TXEN = PA17 - ETHERNET_TX0 = PA18 - ETHERNET_TX1 = PA19 - ETHERNET_RXER = PA15 - ETHERNET_RX0 = PA13 - ETHERNET_RX1 = PA12 - ETHERNET_RXDV = PC20 - ETHERNET_MDIO = PC12 - ETHERNET_MDC = PC11 - ETHERNET_INT = PD12 - ETHERNET_RESET = PC21 - - PIN_QT_BUTTON = PA16 - PIN_BTN0 = PB31 - PIN_ETH_LED = PC15 - PIN_LED0 = PC18 - PIN_ADC_DAC = PA02 - PIN_VBUS_DETECT = PC00 - PIN_USB_ID = PC19 -) - -// USBCDC pins -const ( - USBCDC_DM_PIN = PA24 - USBCDC_DP_PIN = PA25 -) - -// UART pins -const ( - // Extension Header EXT1 - UART_TX_PIN = PA04 // TX : SERCOM0/PAD[0] - UART_RX_PIN = PA05 // RX : SERCOM0/PAD[1] - - // Extension Header EXT2 - UART2_TX_PIN = PB16 // TX : SERCOM5/PAD[0] - UART2_RX_PIN = PB17 // RX : SERCOM5/PAD[1] - - // Extension Header EXT3 - UART3_TX_PIN = PC22 // TX : SERCOM1/PAD[0] - UART3_RX_PIN = PC23 // RX : SERCOM1/PAD[1] - - // Virtual COM Port - UART4_TX_PIN = PB25 // TX : SERCOM2/PAD[0] - UART4_RX_PIN = PB24 // RX : SERCOM2/PAD[1] -) - -// I2C pins -const ( - // Extension Header EXT1 - SDA0_PIN = PA22 // SDA: SERCOM3/PAD[0] - SCL0_PIN = PA23 // SCL: SERCOM3/PAD[1] - - // Extension Header EXT2 - SDA1_PIN = PD08 // SDA: SERCOM7/PAD[0] - SCL1_PIN = PD09 // SCL: SERCOM7/PAD[1] - - // Extension Header EXT3 - SDA2_PIN = PD08 // SDA: SERCOM7/PAD[0] - SCL2_PIN = PD09 // SCL: SERCOM7/PAD[1] - - // Data Gateway Interface - SDA_DGI_PIN = PD08 // SDA: SERCOM7/PAD[0] - SCL_DGI_PIN = PD09 // SCL: SERCOM7/PAD[1] - - SDA_PIN = SDA0_PIN - SCL_PIN = SCL0_PIN -) - -// SPI pins -const ( - // Extension Header EXT1 - SPI0_SCK_PIN = PB26 // SCK: SERCOM4/PAD[1] - SPI0_SDO_PIN = PB27 // SDO: SERCOM4/PAD[0] - SPI0_SDI_PIN = PB29 // SDI: SERCOM4/PAD[3] - SPI0_SS_PIN = PB28 // SS : SERCOM4/PAD[2] - - // Extension Header EXT2 - SPI1_SCK_PIN = PC05 // SCK: SERCOM6/PAD[1] - SPI1_SDO_PIN = PC04 // SDO: SERCOM6/PAD[0] - SPI1_SDI_PIN = PC07 // SDI: SERCOM6/PAD[3] - SPI1_SS_PIN = PC06 // SS : SERCOM6/PAD[2] - - // Extension Header EXT3 - SPI2_SCK_PIN = PC05 // SCK: SERCOM6/PAD[1] - SPI2_SDO_PIN = PC04 // SDO: SERCOM6/PAD[0] - SPI2_SDI_PIN = PC07 // SDI: SERCOM6/PAD[3] - SPI2_SS_PIN = PC14 // SS : GPIO - - // Data Gateway Interface - SPI_DGI_SCK_PIN = PC05 // SCK: SERCOM6/PAD[1] - SPI_DGI_SDO_PIN = PC04 // SDO: SERCOM6/PAD[0] - SPI_DGI_SDI_PIN = PC07 // SDI: SERCOM6/PAD[3] - SPI_DGI_SS_PIN = PD01 // SS : GPIO -) - -// USB CDC identifiers -const ( - usb_STRING_PRODUCT = "SAM E54 Xplained Pro" - usb_STRING_MANUFACTURER = "Atmel" -) - -var ( - usb_VID uint16 = 0x03EB - usb_PID uint16 = 0x2404 -) - -// UART on the SAM E54 Xplained Pro -var ( - // Extension Header EXT1 - UART1 = &sercomUSART0 - - // Extension Header EXT2 - UART2 = &sercomUSART5 - - // Extension Header EXT3 - UART3 = &sercomUSART1 - - // EDBG Virtual COM Port - UART4 = &sercomUSART2 -) - -// I2C on the SAM E54 Xplained Pro -var ( - // Extension Header EXT1 - I2C0 = sercomI2CM3 - - // Extension Header EXT2 - I2C1 = sercomI2CM7 - - // Extension Header EXT3 - I2C2 = sercomI2CM7 - - // Data Gateway Interface - I2C3 = sercomI2CM7 -) - -// SPI on the SAM E54 Xplained Pro -var ( - // Extension Header EXT1 - SPI0 = sercomSPIM4 - - // Extension Header EXT2 - SPI1 = sercomSPIM6 - - // Extension Header EXT3 - SPI2 = sercomSPIM6 - - // Data Gateway Interface - SPI3 = sercomSPIM6 -) - -// CAN on the SAM E54 Xplained Pro -var ( - CAN0 = CAN{ - Bus: sam.CAN0, - } - - CAN1 = CAN{ - Bus: sam.CAN1, - } -) diff --git a/emb/machine/board_badger2040-w.go b/emb/machine/board_badger2040-w.go deleted file mode 100644 index d098265..0000000 --- a/emb/machine/board_badger2040-w.go +++ /dev/null @@ -1,95 +0,0 @@ -//go:build badger2040_w - -// This contains the pin mappings for the Badger 2040 W board. -// -// For more information, see: https://shop.pimoroni.com/products/badger-2040-w -// Also -// - Badger 2040 W schematic: https://cdn.shopify.com/s/files/1/0174/1800/files/badger_w_schematic.pdf?v=1675859004 -package machine - -const ( - LED Pin = GPIO22 - - BUTTON_A Pin = GPIO12 - BUTTON_B Pin = GPIO13 - BUTTON_C Pin = GPIO14 - BUTTON_UP Pin = GPIO15 - BUTTON_DOWN Pin = GPIO11 - BUTTON_USER Pin = NoPin // Not available on Badger 2040 W - - EPD_BUSY_PIN Pin = GPIO26 - EPD_RESET_PIN Pin = GPIO21 - EPD_DC_PIN Pin = GPIO20 - EPD_CS_PIN Pin = GPIO17 - EPD_SCK_PIN Pin = GPIO18 - EPD_SDO_PIN Pin = GPIO19 - - VBUS_DETECT Pin = GPIO24 - VREF_POWER Pin = GPIO27 - VREF_1V24 Pin = GPIO28 - VBAT_SENSE Pin = GPIO29 - ENABLE_3V3 Pin = GPIO10 - - BATTERY = VBAT_SENSE - RTC_ALARM = GPIO8 -) - -// I2C pins -const ( - I2C0_SDA_PIN Pin = GPIO4 - I2C0_SCL_PIN Pin = GPIO5 - - I2C1_SDA_PIN Pin = NoPin - I2C1_SCL_PIN Pin = NoPin -) - -// SPI pins. -const ( - SPI0_SCK_PIN Pin = GPIO18 - SPI0_SDO_PIN Pin = GPIO19 - SPI0_SDI_PIN Pin = GPIO16 - - SPI1_SCK_PIN Pin = NoPin - SPI1_SDO_PIN Pin = NoPin - SPI1_SDI_PIN Pin = NoPin -) - -// QSPI pins¿? -const ( -/* - TODO - -SPI0_SD0_PIN Pin = QSPI_SD0 -SPI0_SD1_PIN Pin = QSPI_SD1 -SPI0_SD2_PIN Pin = QSPI_SD2 -SPI0_SD3_PIN Pin = QSPI_SD3 -SPI0_SCK_PIN Pin = QSPI_SCLKGPIO6 -SPI0_CS_PIN Pin = QSPI_CS -*/ -) - -// Onboard crystal oscillator frequency, in MHz. -const ( - xoscFreq = 12 // MHz -) - -// USB CDC identifiers -const ( - usb_STRING_PRODUCT = "Badger 2040 W" - usb_STRING_MANUFACTURER = "Pimoroni" -) - -var ( - usb_VID uint16 = 0x2e8a - usb_PID uint16 = 0x0003 -) - -// UART pins -const ( - UART0_TX_PIN = GPIO0 - UART0_RX_PIN = GPIO1 - UART_TX_PIN = UART0_TX_PIN - UART_RX_PIN = UART0_RX_PIN -) - -var DefaultUART = UART0 diff --git a/emb/machine/board_badger2040.go b/emb/machine/board_badger2040.go deleted file mode 100644 index 73f802a..0000000 --- a/emb/machine/board_badger2040.go +++ /dev/null @@ -1,94 +0,0 @@ -//go:build badger2040 - -// This contains the pin mappings for the Badger 2040 board. -// -// For more information, see: https://shop.pimoroni.com/products/badger-2040 -// Also -// - Badger 2040 schematic: https://cdn.shopify.com/s/files/1/0174/1800/files/badger_2040_schematic.pdf?v=1645702148 -package machine - -const ( - LED Pin = GPIO25 - - BUTTON_A Pin = GPIO12 - BUTTON_B Pin = GPIO13 - BUTTON_C Pin = GPIO14 - BUTTON_UP Pin = GPIO15 - BUTTON_DOWN Pin = GPIO11 - BUTTON_USER Pin = GPIO23 - - EPD_BUSY_PIN Pin = GPIO26 - EPD_RESET_PIN Pin = GPIO21 - EPD_DC_PIN Pin = GPIO20 - EPD_CS_PIN Pin = GPIO17 - EPD_SCK_PIN Pin = GPIO18 - EPD_SDO_PIN Pin = GPIO19 - - VBUS_DETECT Pin = GPIO24 - VREF_POWER Pin = GPIO27 - VREF_1V24 Pin = GPIO28 - VBAT_SENSE Pin = GPIO29 - ENABLE_3V3 Pin = GPIO10 - - BATTERY = VBAT_SENSE -) - -// I2C pins -const ( - I2C0_SDA_PIN Pin = GPIO4 - I2C0_SCL_PIN Pin = GPIO5 - - I2C1_SDA_PIN Pin = NoPin - I2C1_SCL_PIN Pin = NoPin -) - -// SPI pins. -const ( - SPI0_SCK_PIN Pin = GPIO18 - SPI0_SDO_PIN Pin = GPIO19 - SPI0_SDI_PIN Pin = GPIO16 - - SPI1_SCK_PIN Pin = NoPin - SPI1_SDO_PIN Pin = NoPin - SPI1_SDI_PIN Pin = NoPin -) - -// QSPI pins¿? -const ( -/* - TODO - -SPI0_SD0_PIN Pin = QSPI_SD0 -SPI0_SD1_PIN Pin = QSPI_SD1 -SPI0_SD2_PIN Pin = QSPI_SD2 -SPI0_SD3_PIN Pin = QSPI_SD3 -SPI0_SCK_PIN Pin = QSPI_SCLKGPIO6 -SPI0_CS_PIN Pin = QSPI_CS -*/ -) - -// Onboard crystal oscillator frequency, in MHz. -const ( - xoscFreq = 12 // MHz -) - -// USB CDC identifiers -const ( - usb_STRING_PRODUCT = "Badger 2040" - usb_STRING_MANUFACTURER = "Pimoroni" -) - -var ( - usb_VID uint16 = 0x2e8a - usb_PID uint16 = 0x0003 -) - -// UART pins -const ( - UART0_TX_PIN = GPIO0 - UART0_RX_PIN = GPIO1 - UART_TX_PIN = UART0_TX_PIN - UART_RX_PIN = UART0_RX_PIN -) - -var DefaultUART = UART0 diff --git a/emb/machine/board_bluemicro840.go b/emb/machine/board_bluemicro840.go deleted file mode 100644 index acca709..0000000 --- a/emb/machine/board_bluemicro840.go +++ /dev/null @@ -1,80 +0,0 @@ -//go:build bluemicro840 - -package machine - -const HasLowFrequencyCrystal = true - -// GPIO Pins -const ( - D006 = P0_06 - D008 = P0_08 - D015 = P0_15 - D017 = P0_17 - D020 = P0_20 - D013 = P0_13 - D024 = P0_24 - D009 = P0_09 - D010 = P0_10 - D106 = P1_06 - - D031 = P0_31 // AIN7; P0.31 (AIN7) is used to read the voltage of the battery via ADC. It can’t be used for any other function. - D012 = P0_12 // VCC 3.3V; P0.12 on VCC shuts off the power to VCC when you set it to high; This saves on battery immensely for LEDs of all kinds that eat power even when off - - D030 = P0_30 - D026 = P0_26 - D029 = P0_29 - D002 = P0_02 - D113 = P1_13 - D003 = P0_03 - D028 = P0_28 - D111 = P1_11 -) - -// Analog Pins -const ( - AIN0 = P0_02 - AIN1 = P0_03 - AIN2 = P0_04 // Not Connected - AIN3 = P0_05 // Not Connected - AIN4 = P0_28 - AIN5 = P0_29 - AIN6 = P0_30 - AIN7 = P0_31 // Battery -) - -const ( - LED1 Pin = P1_04 // Red LED - LED2 Pin = P1_10 // Blue LED - LED Pin = LED1 -) - -// UART0 pins (logical UART1) - Maps to same location as Pro Micro -const ( - UART_RX_PIN = P0_08 - UART_TX_PIN = P0_06 -) - -// I2C pins -const ( - SDA_PIN = P0_15 // I2C0 external - SCL_PIN = P0_17 // I2C0 external -) - -// SPI pins -const ( - SPI0_SCK_PIN = P1_13 // SCK - SPI0_SDI_PIN = P0_03 // SDI - SPI0_SDO_PIN = P0_28 // SDO - -) - -// USB CDC identifiers -const ( - usb_STRING_PRODUCT = "bluemicro840" - usb_STRING_MANUFACTURER = "BlueMicro" -) - -var ( - usb_VID uint16 = 0x1d50 - usb_PID uint16 = 0x6161 -) diff --git a/emb/machine/board_bluepill.go b/emb/machine/board_bluepill.go deleted file mode 100644 index 83f527d..0000000 --- a/emb/machine/board_bluepill.go +++ /dev/null @@ -1,110 +0,0 @@ -//go:build bluepill - -package machine - -import ( - "device/stm32" - "runtime/interrupt" -) - -// Pins printed on the silkscreen -const ( - C13 = PC13 - C14 = PC14 - C15 = PC15 - A0 = PA0 - A1 = PA1 - A2 = PA2 - A3 = PA3 - A4 = PA4 - A5 = PA5 - A6 = PA6 - A7 = PA7 - B0 = PB0 - B1 = PB1 - B10 = PB10 - B11 = PB11 - B12 = PB12 - B13 = PB13 - B14 = PB14 - B15 = PB15 - A8 = PA8 - A9 = PA9 - A10 = PA10 - A11 = PA11 - A12 = PA12 - A13 = PA13 - A14 = PA14 - A15 = PA15 - B3 = PB3 - B4 = PB4 - B5 = PB5 - B6 = PB6 - B7 = PB7 - B8 = PB8 - B9 = PB9 -) - -// Analog Pins -const ( - ADC0 = PA0 - ADC1 = PA1 - ADC2 = PA2 - ADC3 = PA3 - ADC4 = PA4 - ADC5 = PA5 - ADC6 = PA6 - ADC7 = PA7 - ADC8 = PB0 - ADC9 = PB1 -) - -const ( - // This board does not have a user button, so - // use first GPIO pin by default - BUTTON = PA0 - - LED = PC13 -) - -var DefaultUART = UART1 - -// UART pins -const ( - UART_TX_PIN = PA9 - UART_RX_PIN = PA10 - UART_ALT_TX_PIN = PB6 - UART_ALT_RX_PIN = PB7 -) - -var ( - // USART1 is the first hardware serial port on the STM32. - UART1 = &_UART1 - _UART1 = UART{ - Buffer: NewRingBuffer(), - Bus: stm32.USART1, - } - UART2 = &_UART2 - _UART2 = UART{ - Buffer: NewRingBuffer(), - Bus: stm32.USART2, - } -) - -func init() { - UART1.Interrupt = interrupt.New(stm32.IRQ_USART1, _UART1.handleInterrupt) - UART2.Interrupt = interrupt.New(stm32.IRQ_USART2, _UART2.handleInterrupt) -} - -// SPI pins -const ( - SPI0_SCK_PIN = PA5 - SPI0_SDO_PIN = PA7 - SPI0_SDI_PIN = PA6 -) - -// I2C pins -const ( - I2C0_SDA_PIN = PB7 - I2C0_SCL_PIN = PB6 -) diff --git a/emb/machine/board_btt_skr_pico.go b/emb/machine/board_btt_skr_pico.go deleted file mode 100644 index 6036ad9..0000000 --- a/emb/machine/board_btt_skr_pico.go +++ /dev/null @@ -1,121 +0,0 @@ -//go:build btt_skr_pico - -// This contains the pin mappings for the BigTreeTech SKR Pico. -// -// Purchase link: https://biqu.equipment/products/btt-skr-pico-v1-0 -// Board schematic: https://github.com/bigtreetech/SKR-Pico/blob/master/Hardware/BTT%20SKR%20Pico%20V1.0-SCH.pdf -// Pin diagram: https://github.com/bigtreetech/SKR-Pico/blob/master/Hardware/BTT%20SKR%20Pico%20V1.0-PIN.pdf - -package machine - -// TMC stepper driver motor direction. -// X/Y/Z/E refers to motors for X/Y/Z and the extruder. -const ( - X_DIR = GPIO10 - Y_DIR = GPIO5 - Z_DIR = GPIO28 - E_DIR = GPIO13 -) - -// TMC stepper driver motor step -const ( - X_STEP = GPIO11 - Y_STEP = GPIO6 - Z_STEP = GPIO19 - E_STEP = GPIO14 -) - -// TMC stepper driver enable -const ( - X_ENABLE = GPIO12 - Y_ENABLE = GPIO7 - Z_ENABLE = GPIO2 - E_ENABLE = GPIO15 -) - -// TMC stepper driver UART -const ( - TMC_UART_TX = UART1_TX_PIN - TMC_UART_RX = UART1_RX_PIN -) - -// Endstops -const ( - X_ENDSTOP = GPIO4 - Y_ENDSTOP = GPIO3 - Z_ENDSTOP = GPIO25 - E_ENDSTOP = GPIO16 -) - -// Fan PWM -const ( - FAN1_PWM = GPIO17 - FAN2_PWM = GPIO18 - FAN3_PWM = GPIO20 -) - -// Heater PWM -const ( - HEATER_BED_PWM = GPIO21 - HEATER_EXTRUDER_PWM = GPIO23 -) - -// Thermistors -const ( - THERM_BED = GPIO26 // Bed heater - THERM_EXTRUDER = GPIO27 // Toolhead heater -) - -// Misc -const ( - RGB = GPIO24 // Neopixel - SERVO = GPIO29 // Servo - PROBE = GPIO22 // Probe -) - -// Onboard crystal oscillator frequency, in MHz. -const ( - xoscFreq = 12 // MHz -) - -// I2C. We don't have this available -const ( - I2C0_SDA_PIN = NoPin - I2C0_SCL_PIN = NoPin - - I2C1_SDA_PIN = NoPin - I2C1_SCL_PIN = NoPin -) - -// SPI. We don't have this available -const ( - SPI0_SCK_PIN = NoPin - SPI0_SDO_PIN = NoPin - SPI0_SDI_PIN = NoPin - SPI1_SCK_PIN = NoPin - SPI1_SDO_PIN = NoPin - SPI1_SDI_PIN = NoPin -) - -// USB CDC identifiers -const ( - usb_STRING_PRODUCT = "SKR Pico" - usb_STRING_MANUFACTURER = "BigTreeTech" -) - -var ( - usb_VID uint16 = 0x2e8a - usb_PID uint16 = 0x0003 -) - -// UART pins -const ( - UART0_TX_PIN = GPIO0 - UART0_RX_PIN = GPIO1 - UART1_TX_PIN = GPIO8 - UART1_RX_PIN = GPIO9 - UART_TX_PIN = UART0_TX_PIN - UART_RX_PIN = UART0_RX_PIN -) - -var DefaultUART = UART0 diff --git a/emb/machine/board_challenger_rp2040.go b/emb/machine/board_challenger_rp2040.go deleted file mode 100644 index 9a85aa0..0000000 --- a/emb/machine/board_challenger_rp2040.go +++ /dev/null @@ -1,93 +0,0 @@ -//go:build challenger_rp2040 - -package machine - -const ( - LED = GPIO24 - - // Onboard crystal oscillator frequency, in MHz. - xoscFreq = 12 // MHz -) - -// GPIO Pins -const ( - D5 = GPIO2 - D6 = GPIO3 - D9 = GPIO4 - D10 = GPIO5 - D11 = GPIO6 - D12 = GPIO7 - D13 = GPIO8 -) - -// Analog pins -const ( - A0 = ADC0 - A1 = ADC1 - A2 = ADC2 - A3 = ADC3 -) - -// I2C Pins. -const ( - I2C0_SDA_PIN = GPIO24 - I2C0_SCL_PIN = GPIO25 - - I2C1_SDA_PIN = GPIO2 - I2C1_SCL_PIN = GPIO3 - - SDA_PIN = I2C1_SDA_PIN - SCL_PIN = I2C1_SCL_PIN -) - -// SPI default pins -const ( - // Default Serial Clock Bus 0 for SPI communications - SPI0_SCK_PIN = GPIO22 - // Default Serial Out Bus 0 for SPI communications - SPI0_SDO_PIN = GPIO23 // Tx - // Default Serial In Bus 0 for SPI communications - SPI0_SDI_PIN = GPIO20 // Rx - - // Default Serial Clock Bus 1 for SPI communications - SPI1_SCK_PIN = GPIO10 - // Default Serial Out Bus 1 for SPI communications - SPI1_SDO_PIN = GPIO11 // Tx - // Default Serial In Bus 1 for SPI communications - SPI1_SDI_PIN = GPIO12 // Rx -) - -// LoRa default pins -const ( - LORA_CS = GPIO9 - LORA_SCK = GPIO10 - LORA_SDO = GPIO11 - LORA_SDI = GPIO12 - LORA_RESET = GPIO13 - LORA_DIO0 = GPIO14 - LORA_DIO1 = GPIO15 - LORA_DIO2 = GPIO18 -) - -// UART pins -const ( - UART0_TX_PIN = GPIO16 - UART0_RX_PIN = GPIO17 - UART1_TX_PIN = GPIO4 - UART1_RX_PIN = GPIO5 - UART_TX_PIN = UART0_TX_PIN - UART_RX_PIN = UART0_RX_PIN -) - -var DefaultUART = UART0 - -// USB identifiers -const ( - usb_STRING_PRODUCT = "Challenger 2040 LoRa" - usb_STRING_MANUFACTURER = "iLabs" -) - -var ( - usb_VID uint16 = 0x2e8a - usb_PID uint16 = 0x1023 -) diff --git a/emb/machine/board_circuitplay_bluefruit.go b/emb/machine/board_circuitplay_bluefruit.go deleted file mode 100644 index a133003..0000000 --- a/emb/machine/board_circuitplay_bluefruit.go +++ /dev/null @@ -1,95 +0,0 @@ -//go:build circuitplay_bluefruit - -package machine - -const HasLowFrequencyCrystal = false - -// GPIO Pins -const ( - D0 = P0_30 - D1 = P0_14 - D2 = P0_05 - D3 = P0_04 - D4 = P1_02 - D5 = P1_15 - D6 = P0_02 - D7 = P1_06 - D8 = P0_13 - D9 = P0_29 - D10 = P0_03 - D11 = P1_04 - D12 = P0_26 - D13 = P1_14 -) - -// Analog Pins -const ( - A1 = P0_02 - A2 = P0_29 - A3 = P0_03 - A4 = P0_04 - A5 = P0_05 - A6 = P0_30 - A7 = P0_14 - A8 = P0_28 - A9 = P0_31 -) - -const ( - LED = D13 - NEOPIXELS = D8 - WS2812 = D8 - - BUTTONA = D4 - BUTTONB = D5 - SLIDER = D7 // built-in slide switch - - BUTTON = BUTTONA - BUTTON1 = BUTTONB - - LIGHTSENSOR = A8 - TEMPSENSOR = A9 -) - -// UART0 pins (logical UART1) -const ( - UART_TX_PIN = P0_14 // PORTB - UART_RX_PIN = P0_30 // PORTB -) - -// I2C pins -const ( - SDA_PIN = P0_05 // I2C0 external - SCL_PIN = P0_04 // I2C0 external - - SDA1_PIN = P1_10 // I2C1 internal - SCL1_PIN = P1_12 // I2C1 internal -) - -// SPI pins (internal flash) -const ( - SPI0_SCK_PIN = P0_19 // SCK - SPI0_SDO_PIN = P0_21 // SDO - SPI0_SDI_PIN = P0_23 // SDI -) - -// PDM pins -const ( - PDM_CLK_PIN = P0_17 // CLK - PDM_DIN_PIN = P0_16 // DIN -) - -// USB CDC identifiers -const ( - usb_STRING_PRODUCT = "Adafruit Circuit Playground Bluefruit" - usb_STRING_MANUFACTURER = "Adafruit" -) - -var ( - usb_VID uint16 = 0x239A - usb_PID uint16 = 0x8045 -) - -var ( - DefaultUART = UART0 -) diff --git a/emb/machine/board_circuitplay_express.go b/emb/machine/board_circuitplay_express.go deleted file mode 100644 index ce1f29c..0000000 --- a/emb/machine/board_circuitplay_express.go +++ /dev/null @@ -1,119 +0,0 @@ -//go:build circuitplay_express - -package machine - -// used to reset into bootloader -const resetMagicValue = 0xf01669ef - -// GPIO Pins -const ( - D0 = PB09 - D1 = PB08 - D2 = PB02 - D3 = PB03 - D4 = PA28 - D5 = PA14 - D6 = PA05 - D7 = PA15 - D8 = PB23 - D9 = PA06 - D10 = PA07 - D11 = NoPin // does not seem to exist - D12 = PA02 - D13 = PA17 // PWM available -) - -// Analog Pins -const ( - A0 = PA02 // ADC/AIN[0] - A1 = PA05 // PWM available, also ADC/AIN[5] - A2 = PA06 // PWM available, also ADC/AIN[6] - A3 = PA07 // PWM available, also ADC/AIN[7] - A4 = PB03 // PORTB - A5 = PB02 // PORTB - A6 = PB09 // PORTB - A7 = PB08 // PORTB - A8 = PA11 // ADC/AIN[19] - A9 = PA09 // ADC/AIN[17] - A10 = PA04 -) - -const ( - LED = D13 - NEOPIXELS = D8 - WS2812 = D8 - - BUTTONA = D4 - BUTTONB = D5 - SLIDER = D7 // built-in slide switch - - BUTTON = BUTTONA - BUTTON1 = BUTTONB - - LIGHTSENSOR = A8 - TEMPSENSOR = A9 - PROXIMITY = A10 -) - -// USBCDC pins (logical UART0) -const ( - USBCDC_DM_PIN = PA24 - USBCDC_DP_PIN = PA25 -) - -// UART0 pins (logical UART1) -const ( - UART_TX_PIN = PB08 // PORTB - UART_RX_PIN = PB09 // PORTB -) - -// UART1 on the Circuit Playground Express. -var ( - UART1 = &sercomUSART4 - - DefaultUART = UART1 -) - -// I2C pins -const ( - SDA_PIN = PB02 // I2C0 external - SCL_PIN = PB03 // I2C0 external - - SDA1_PIN = PA00 // I2C1 internal - SCL1_PIN = PA01 // I2C1 internal -) - -// I2C on the Circuit Playground Express. -var ( - I2C0 = sercomI2CM5 // external device - I2C1 = sercomI2CM1 // internal device -) - -// SPI pins (internal flash) -const ( - SPI0_SCK_PIN = PA21 // SCK: SERCOM3/PAD[3] - SPI0_SDO_PIN = PA20 // SDO: SERCOM3/PAD[2] - SPI0_SDI_PIN = PA16 // SDI: SERCOM3/PAD[0] -) - -// SPI on the Circuit Playground Express. -var SPI0 = sercomSPIM3 - -// I2S pins -const ( - I2S_SCK_PIN = PA10 - I2S_SDO_PIN = PA08 - I2S_SDI_PIN = NoPin - I2S_WS_PIN = NoPin // no WS, instead uses SCK to sync -) - -// USB CDC identifiers -const ( - usb_STRING_PRODUCT = "Adafruit Circuit Playground Express" - usb_STRING_MANUFACTURER = "Adafruit" -) - -var ( - usb_VID uint16 = 0x239A - usb_PID uint16 = 0x8018 -) diff --git a/emb/machine/board_clue_alpha.go b/emb/machine/board_clue_alpha.go deleted file mode 100644 index 8d16f4e..0000000 --- a/emb/machine/board_clue_alpha.go +++ /dev/null @@ -1,125 +0,0 @@ -//go:build clue_alpha - -package machine - -const HasLowFrequencyCrystal = false - -// GPIO Pins -const ( - D0 = P0_04 - D1 = P0_05 - D2 = P0_03 - D3 = P0_28 - D4 = P0_02 - D5 = P1_02 - D6 = P1_09 - D7 = P0_07 - D8 = P1_07 - D9 = P0_27 - D10 = P0_30 - D11 = P1_10 - D12 = P0_31 - D13 = P0_08 - D14 = P0_06 - D15 = P0_26 - D16 = P0_29 - D17 = P1_01 - D18 = P0_16 - D19 = P0_25 - D20 = P0_24 - D29 = P0_14 - D30 = P0_15 - D31 = P0_12 - D32 = P0_13 - D33 = P1_03 - D34 = P1_05 - D35 = P0_00 - D36 = P0_01 - D37 = P0_19 - D38 = P0_20 - D39 = P0_17 - D40 = P0_22 - D41 = P0_23 - D42 = P0_21 - D43 = P0_10 - D44 = P0_09 - D45 = P1_06 - D46 = P1_00 -) - -// Analog Pins -const ( - A0 = D12 - A1 = D16 - A2 = D0 - A3 = D1 - A4 = D2 - A5 = D3 - A6 = D4 - A7 = D10 -) - -const ( - LED = D17 - LED1 = LED - LED2 = D43 - NEOPIXEL = D18 - WS2812 = D18 - - BUTTON_LEFT = D5 - BUTTON_RIGHT = D11 - - // 240x240 ST7789 display is connected to these pins (use RowOffset = 80) - TFT_SCK = D29 - TFT_SDO = D30 - TFT_CS = D31 - TFT_DC = D32 - TFT_RESET = D33 - TFT_LITE = D34 - - PDM_DAT = D35 - PDM_CLK = D36 - - QSPI_SCK = D37 - QSPI_CS = D38 - QSPI_DATA0 = D39 - QSPI_DATA1 = D40 - QSPI_DATA2 = D41 - QSPI_DATA3 = D42 - - SPEAKER = D46 -) - -// UART0 pins (logical UART1) -const ( - UART_RX_PIN = D0 - UART_TX_PIN = D1 -) - -// I2C pins -const ( - SDA_PIN = D20 // I2C0 external - SCL_PIN = D19 // I2C0 external -) - -// SPI pins -const ( - SPI0_SCK_PIN = D13 // SCK - SPI0_SDO_PIN = D15 // SDO - SPI0_SDI_PIN = D14 // SDI -) - -// USB CDC identifiers -const ( - usb_STRING_PRODUCT = "Adafruit CLUE" - usb_STRING_MANUFACTURER = "Adafruit" -) - -var ( - usb_VID uint16 = 0x239A - usb_PID uint16 = 0x8072 -) - -var ( - DefaultUART = UART0 -) diff --git a/emb/machine/board_digispark.go b/emb/machine/board_digispark.go deleted file mode 100644 index f380aae..0000000 --- a/emb/machine/board_digispark.go +++ /dev/null @@ -1,19 +0,0 @@ -//go:build digispark - -package machine - -// Return the current CPU frequency in hertz. -func CPUFrequency() uint32 { - return 16000000 -} - -const ( - P0 Pin = PB0 - P1 Pin = PB1 - P2 Pin = PB2 - P3 Pin = PB3 - P4 Pin = PB4 - P5 Pin = PB5 - - LED = P1 -) diff --git a/emb/machine/board_elecrow-rp2040-w5.go b/emb/machine/board_elecrow-rp2040-w5.go deleted file mode 100644 index 1ea0181..0000000 --- a/emb/machine/board_elecrow-rp2040-w5.go +++ /dev/null @@ -1,94 +0,0 @@ -//go:build elecrow_rp2040 - -// This file contains the pin mappings for the Elecrow Pico rp2040 W5 boards. -// -// Elecrow Pico rp2040 W5 is a microcontroller using the Raspberry Pi RP2040 -// chip and rtl8720d Wifi chip. -// -// - https://www.elecrow.com/wiki/PICO_W5_RP2040_Dev_Board.html -package machine - -// GPIO pins -const ( - GP0 Pin = GPIO0 - GP1 Pin = GPIO1 - GP2 Pin = GPIO2 - GP3 Pin = GPIO3 - GP4 Pin = GPIO4 - GP5 Pin = GPIO5 - GP6 Pin = GPIO6 - GP7 Pin = GPIO7 - GP8 Pin = GPIO8 - GP9 Pin = GPIO9 - GP10 Pin = GPIO10 - GP11 Pin = GPIO11 - GP12 Pin = GPIO12 - GP13 Pin = GPIO13 - GP14 Pin = GPIO14 - GP15 Pin = GPIO15 - GP16 Pin = GPIO16 - GP17 Pin = GPIO17 - GP18 Pin = GPIO18 - GP19 Pin = GPIO19 - GP20 Pin = GPIO20 - GP21 Pin = GPIO21 - GP22 Pin = GPIO22 - GP26 Pin = GPIO26 - GP27 Pin = GPIO27 - GP28 Pin = GPIO28 - - // Onboard LED - LED Pin = GPIO25 - - // Onboard crystal oscillator frequency, in MHz. - xoscFreq = 12 // MHz -) - -// I2C Default pins on Raspberry Pico. -const ( - I2C0_SDA_PIN = GP4 - I2C0_SCL_PIN = GP5 - - I2C1_SDA_PIN = GP2 - I2C1_SCL_PIN = GP3 -) - -// SPI default pins -const ( - // Default Serial Clock Bus 0 for SPI communications - SPI0_SCK_PIN = GPIO18 - // Default Serial Out Bus 0 for SPI communications - SPI0_SDO_PIN = GPIO19 // Tx - // Default Serial In Bus 0 for SPI communications - SPI0_SDI_PIN = GPIO16 // Rx - - // Default Serial Clock Bus 1 for SPI communications - SPI1_SCK_PIN = GPIO10 - // Default Serial Out Bus 1 for SPI communications - SPI1_SDO_PIN = GPIO11 // Tx - // Default Serial In Bus 1 for SPI communications - SPI1_SDI_PIN = GPIO12 // Rx -) - -// UART pins -const ( - UART0_TX_PIN = GPIO0 - UART0_RX_PIN = GPIO1 - UART1_TX_PIN = GPIO4 // Wired to rtl8720d UART1_Tx - UART1_RX_PIN = GPIO5 // Wired to rtl8720n UART1_Rx - UART_TX_PIN = UART0_TX_PIN - UART_RX_PIN = UART0_RX_PIN -) - -var DefaultUART = UART0 - -// USB identifiers -const ( - usb_STRING_PRODUCT = "Pico" - usb_STRING_MANUFACTURER = "Raspberry Pi" -) - -var ( - usb_VID uint16 = 0x2E8A - usb_PID uint16 = 0x000A -) diff --git a/emb/machine/board_elecrow-rp2350-w5.go b/emb/machine/board_elecrow-rp2350-w5.go deleted file mode 100644 index 80a8436..0000000 --- a/emb/machine/board_elecrow-rp2350-w5.go +++ /dev/null @@ -1,94 +0,0 @@ -//go:build elecrow_rp2350 - -// This file contains the pin mappings for the Elecrow Pico rp2350 W5 boards. -// -// Elecrow Pico rp2350 W5 is a microcontroller using the Raspberry Pi RP2350 -// chip and rtl8720d Wifi chip. -// -// - https://www.elecrow.com/pico-w5-microcontroller-development-boards-rp2350-microcontroller-board.html -package machine - -// GPIO pins -const ( - GP0 Pin = GPIO0 - GP1 Pin = GPIO1 - GP2 Pin = GPIO2 - GP3 Pin = GPIO3 - GP4 Pin = GPIO4 - GP5 Pin = GPIO5 - GP6 Pin = GPIO6 - GP7 Pin = GPIO7 - GP8 Pin = GPIO8 - GP9 Pin = GPIO9 - GP10 Pin = GPIO10 - GP11 Pin = GPIO11 - GP12 Pin = GPIO12 - GP13 Pin = GPIO13 - GP14 Pin = GPIO14 - GP15 Pin = GPIO15 - GP16 Pin = GPIO16 - GP17 Pin = GPIO17 - GP18 Pin = GPIO18 - GP19 Pin = GPIO19 - GP20 Pin = GPIO20 - GP21 Pin = GPIO21 - GP22 Pin = GPIO22 - GP26 Pin = GPIO26 - GP27 Pin = GPIO27 - GP28 Pin = GPIO28 - - // Onboard LED - LED Pin = GPIO25 - - // Onboard crystal oscillator frequency, in MHz. - xoscFreq = 12 // MHz -) - -// I2C Default pins on Raspberry Pico. -const ( - I2C0_SDA_PIN = GP4 - I2C0_SCL_PIN = GP5 - - I2C1_SDA_PIN = GP2 - I2C1_SCL_PIN = GP3 -) - -// SPI default pins -const ( - // Default Serial Clock Bus 0 for SPI communications - SPI0_SCK_PIN = GPIO18 - // Default Serial Out Bus 0 for SPI communications - SPI0_SDO_PIN = GPIO19 // Tx - // Default Serial In Bus 0 for SPI communications - SPI0_SDI_PIN = GPIO16 // Rx - - // Default Serial Clock Bus 1 for SPI communications - SPI1_SCK_PIN = GPIO10 - // Default Serial Out Bus 1 for SPI communications - SPI1_SDO_PIN = GPIO11 // Tx - // Default Serial In Bus 1 for SPI communications - SPI1_SDI_PIN = GPIO12 // Rx -) - -// UART pins -const ( - UART0_TX_PIN = GPIO0 - UART0_RX_PIN = GPIO1 - UART1_TX_PIN = GPIO4 // Wired to rtl8720d UART1_Tx - UART1_RX_PIN = GPIO5 // Wired to rtl8720n UART1_Rx - UART_TX_PIN = UART0_TX_PIN - UART_RX_PIN = UART0_RX_PIN -) - -var DefaultUART = UART0 - -// USB identifiers -const ( - usb_STRING_PRODUCT = "Pico2" - usb_STRING_MANUFACTURER = "Raspberry Pi" -) - -var ( - usb_VID uint16 = 0x2E8A - usb_PID uint16 = 0x000F -) diff --git a/emb/machine/board_esp-c3-32s-kit.go b/emb/machine/board_esp-c3-32s-kit.go deleted file mode 100644 index 09385aa..0000000 --- a/emb/machine/board_esp-c3-32s-kit.go +++ /dev/null @@ -1,40 +0,0 @@ -//go:build esp_c3_32s_kit - -package machine - -// See: -// * https://www.waveshare.com/w/upload/8/8f/Esp32-c3s_specification.pdf -// * https://www.waveshare.com/w/upload/4/46/Nodemcu-esp-c3-32s-kit-schematics.pdf - -// Digital Pins -const ( - IO0 = GPIO0 - IO1 = GPIO1 - IO2 = GPIO2 - IO3 = GPIO3 - IO4 = GPIO4 - IO5 = GPIO5 - IO6 = GPIO6 - IO7 = GPIO7 - IO8 = GPIO8 - IO9 = GPIO9 - IO18 = GPIO18 - IO19 = GPIO19 -) - -const ( - LED_RED = IO3 - LED_GREEN = IO4 - LED_BLUE = IO5 - - LED = LED_RED - - LED1 = LED_RED - LED2 = LED_GREEN -) - -// I2C pins -const ( - SDA_PIN = NoPin - SCL_PIN = NoPin -) diff --git a/emb/machine/board_esp32-c3-devkit-rust-1.go b/emb/machine/board_esp32-c3-devkit-rust-1.go deleted file mode 100644 index 8e47269..0000000 --- a/emb/machine/board_esp32-c3-devkit-rust-1.go +++ /dev/null @@ -1,81 +0,0 @@ -//go:build esp32_c3_devkit_rust_1 - -// This file contains the pin mappings for the Espressif ESP32-C3 Development Board for Rust. -// -// The Espressif ESP32-C3-DevKit-RUST-1 development board is powered -// by the Espressif ESP32-C3 SoC featuring an open-source RISC-V architecture. -// -// Specifications: -// SoC: ESP32-C3-MINI-1, 4MB Flash, RISCV-32bit, 160MHz, 400KB SRAM -// Wireless: WiFi & Bluetooth 5.0 (BLE) -// ICM-42670-P 6-Axis IMU (I2C Addr 0x68) -// SHTC3 Humidity and Temperature Sensor (I2C Addr 0x70) -// WS2812B LED - -// GitHub: https://github.com/esp-rs/esp-rust-board -// Schematic: https://github.com/esp-rs/esp-rust-board/blob/master/hardware/esp-rust-board/schematic/esp-rust-board.pdf -// Datasheet: https://www.espressif.com/sites/default/files/documentation/esp32-c3_datasheet_en.pdf - -package machine - -// Digital pins -const ( - // Pin // Function - // ----- // --------------- - D0 = GPIO0 // - D1 = GPIO1 // - D2 = GPIO2 // WS2812 - D3 = GPIO3 // - D4 = GPIO4 // MTMS - D5 = GPIO5 // MTDI - D6 = GPIO6 // MTCK - D7 = GPIO7 // Red LED / MTDO - D8 = GPIO8 // I2C SCL - D9 = GPIO9 // Boot Button - D10 = GPIO10 // I2C SDA - D18 = GPIO18 // USB DM - D19 = GPIO19 // USB DP - D20 = GPIO20 // UART RX - D21 = GPIO21 // UART TX -) - -// Analog pins -const ( - A0 = GPIO0 - A1 = GPIO1 - A2 = GPIO2 - A3 = GPIO3 - A4 = GPIO4 - A5 = GPIO5 -) - -// Button pin -const ( - BUTTON = BUTTON_BOOT - BUTTON_BOOT = D9 -) - -// LED pins -const ( - LED = LED_BUILTIN - WS2812 = D2 - LED_BUILTIN = D7 -) - -// I2C pins -const ( - SCL_PIN = D8 - SDA_PIN = D10 -) - -// USBCDC pins -const ( - USBCDC_DM_PIN = D18 - USBCDC_DP_PIN = D19 -) - -// UART pins -const ( - UART_RX_PIN = D20 - UART_TX_PIN = D21 -) diff --git a/emb/machine/board_esp32-coreboard-v2.go b/emb/machine/board_esp32-coreboard-v2.go deleted file mode 100644 index 044d906..0000000 --- a/emb/machine/board_esp32-coreboard-v2.go +++ /dev/null @@ -1,88 +0,0 @@ -//go:build esp32_coreboard_v2 - -package machine - -const ( - CLK = GPIO6 - CMD = GPIO11 - IO0 = GPIO0 - IO1 = GPIO1 - IO2 = GPIO2 - IO3 = GPIO3 - IO4 = GPIO4 - IO5 = GPIO5 - IO9 = GPIO9 - IO10 = GPIO10 - IO16 = GPIO16 - IO17 = GPIO17 - IO18 = GPIO18 - IO19 = GPIO19 - IO21 = GPIO21 - IO22 = GPIO22 - IO23 = GPIO23 - IO25 = GPIO25 - IO26 = GPIO26 - IO27 = GPIO27 - IO32 = GPIO32 - IO33 = GPIO33 - IO34 = GPIO34 - IO35 = GPIO35 - IO36 = GPIO36 - IO39 = GPIO39 - RXD = GPIO3 - SD0 = GPIO7 - SD1 = GPIO8 - SD2 = GPIO9 - SD3 = GPIO10 - SVN = GPIO39 - SVP = GPIO36 - TCK = GPIO13 - TD0 = GPIO15 - TDI = GPIO12 - TMS = GPIO14 - TXD = GPIO1 -) - -// Built-in LED on some ESP32 boards. -const LED = IO2 - -// SPI pins -const ( - SPI0_SCK_PIN = IO18 - SPI0_SDO_PIN = IO23 - SPI0_SDI_PIN = IO19 - SPI0_CS0_PIN = IO5 -) - -// I2C pins -const ( - SDA_PIN = IO21 - SCL_PIN = IO22 -) - -// ADC pins -const ( - ADC0 Pin = IO34 - ADC1 Pin = IO35 - ADC2 Pin = IO36 - ADC3 Pin = IO39 -) - -// UART0 pins -const ( - UART_TX_PIN = IO1 - UART_RX_PIN = IO3 -) - -// UART1 pins -const ( - UART1_TX_PIN = IO9 - UART1_RX_PIN = IO10 -) - -// PWM pins -const ( - PWM0_PIN Pin = IO2 - PWM1_PIN Pin = IO0 - PWM2_PIN Pin = IO4 -) diff --git a/emb/machine/board_esp32c3-12f.go b/emb/machine/board_esp32c3-12f.go deleted file mode 100644 index f023bb9..0000000 --- a/emb/machine/board_esp32c3-12f.go +++ /dev/null @@ -1,54 +0,0 @@ -//go:build esp32c312f - -package machine - -// Built-in RGB LED -const ( - LED_RED = IO3 - LED_GREEN = IO4 - LED_BLUE = IO5 - LED = LED_RED -) - -const ( - IO0 = GPIO0 - IO1 = GPIO1 - IO2 = GPIO2 - IO3 = GPIO3 - IO4 = GPIO4 - IO5 = GPIO5 - IO6 = GPIO6 - IO7 = GPIO7 - IO8 = GPIO8 - IO9 = GPIO9 - IO10 = GPIO10 - IO18 = GPIO18 - IO19 = GPIO19 - RXD = GPIO20 - TXD = GPIO21 -) - -// ADC pins -const ( - ADC0 Pin = ADC1_0 - ADC1 Pin = ADC2_0 - - ADC1_0 Pin = IO0 - ADC1_1 Pin = IO1 - ADC1_2 Pin = IO2 - ADC1_3 Pin = IO3 - ADC1_4 Pin = IO4 - ADC2_0 Pin = IO5 -) - -// UART0 pins -const ( - UART_TX_PIN = TXD - UART_RX_PIN = RXD -) - -// I2C pins -const ( - SCL_PIN = NoPin - SDA_PIN = NoPin -) diff --git a/emb/machine/board_esp32c3-supermini.go b/emb/machine/board_esp32c3-supermini.go deleted file mode 100644 index c180ff0..0000000 --- a/emb/machine/board_esp32c3-supermini.go +++ /dev/null @@ -1,57 +0,0 @@ -//go:build esp32c3_supermini - -// This file contains the pin mappings for the ESP32 supermini boards. -// -// - https://web.archive.org/web/20240805232453/https://dl.artronshop.co.th/ESP32-C3%20SuperMini%20datasheet.pdf - -package machine - -// Digital Pins -const ( - IO0 = GPIO0 - IO1 = GPIO1 - IO2 = GPIO2 - IO3 = GPIO3 - IO4 = GPIO4 - IO5 = GPIO5 - IO6 = GPIO6 - IO7 = GPIO7 - IO8 = GPIO8 - IO9 = GPIO9 - IO10 = GPIO10 - IO20 = GPIO20 - IO21 = GPIO21 -) - -// Built-in LED -const LED = GPIO8 - -// Analog pins -const ( - A0 = GPIO0 - A1 = GPIO1 - A2 = GPIO2 - A3 = GPIO3 - A4 = GPIO4 - A5 = GPIO5 -) - -// UART pins -const ( - UART_RX_PIN = GPIO20 - UART_TX_PIN = GPIO21 -) - -// I2C pins -const ( - SDA_PIN = GPIO8 - SCL_PIN = GPIO9 -) - -// SPI pins -const ( - SPI_MISO_PIN = GPIO5 - SPI_MOSI_PIN = GPIO6 - SPI_SS_PIN = GPIO7 - SPI_SCK_PIN = GPIO4 -) diff --git a/emb/machine/board_fe310.go b/emb/machine/board_fe310.go deleted file mode 100644 index 8881015..0000000 --- a/emb/machine/board_fe310.go +++ /dev/null @@ -1,38 +0,0 @@ -//go:build hifive1b - -package machine - -const ( - P00 Pin = 0 - P01 Pin = 1 - P02 Pin = 2 - P03 Pin = 3 - P04 Pin = 4 - P05 Pin = 5 - P06 Pin = 6 - P07 Pin = 7 - P08 Pin = 8 - P09 Pin = 9 - P10 Pin = 10 - P11 Pin = 11 - P12 Pin = 12 - P13 Pin = 13 - P14 Pin = 14 - P15 Pin = 15 - P16 Pin = 16 - P17 Pin = 17 - P18 Pin = 18 - P19 Pin = 19 - P20 Pin = 20 - P21 Pin = 21 - P22 Pin = 22 - P23 Pin = 23 - P24 Pin = 24 - P25 Pin = 25 - P26 Pin = 26 - P27 Pin = 27 - P28 Pin = 28 - P29 Pin = 29 - P30 Pin = 30 - P31 Pin = 31 -) diff --git a/emb/machine/board_feather-m0-express.go b/emb/machine/board_feather-m0-express.go deleted file mode 100644 index 226369f..0000000 --- a/emb/machine/board_feather-m0-express.go +++ /dev/null @@ -1,102 +0,0 @@ -//go:build sam && atsamd21 && feather_m0_express - -package machine - -// used to reset into bootloader -const resetMagicValue = 0xf01669ef - -// GPIO Pins -const ( - D0 = PA11 // UART0 RX - D1 = PA10 // UART0 TX - D2 = NoPin // does not seem to exist - D3 = NoPin // does not seem to exist - D4 = NoPin // does not seem to exist - D5 = PA15 - D6 = PA20 - D7 = NoPin // does not seem to exist - D8 = PA06 // NEOPIXEL - D9 = PA07 - D10 = PA18 - D11 = PA16 - D12 = PA19 - D13 = PA17 -) - -// Analog pins -const ( - A0 = PA02 // ADC/AIN[0] - A1 = PB08 // ADC/AIN[2] - A2 = PB09 // ADC/AIN[3] - A3 = PA04 // ADC/AIN[4] - A4 = PA05 // ADC/AIN[5] - A5 = PB02 // ADC/AIN[10] -) - -const ( - LED = D13 - NEOPIXEL = D8 -) - -// USBCDC pins -const ( - USBCDC_DM_PIN = PA24 - USBCDC_DP_PIN = PA25 -) - -// UART1 pins -const ( - UART_TX_PIN = D1 - UART_RX_PIN = D0 - - UART1_TX_PIN = D10 - UART1_RX_PIN = D12 -) - -// UART0 on the Feather M0 Express. -var UART0 = &sercomUSART0 -var UART1 = &sercomUSART1 - -// I2C pins -const ( - SDA_PIN = PA22 // SDA: SERCOM3/PAD[0] - SCL_PIN = PA23 // SCL: SERCOM3/PAD[1] -) - -// I2C on the Feather M0 Express. -var ( - I2C0 = sercomI2CM3 -) - -// SPI pins -const ( - SPI0_SCK_PIN = PB11 // SCK: SERCOM4/PAD[3] - SPI0_SDO_PIN = PB10 // SDO: SERCOM4/PAD[2] - SPI0_SDI_PIN = PA12 // SDI: SERCOM4/PAD[0] -) - -// SPI on the Feather M0. -var SPI0 = sercomSPIM4 - -// I2S pins -const ( - I2S_SCK_PIN = PA10 - I2S_SDO_PIN = PA07 - I2S_SDI_PIN = NoPin - I2S_WS_PIN = NoPin // TODO: figure out what this is on Feather M0 Express. -) - -// USB CDC identifiers -const ( - usb_STRING_PRODUCT = "Adafruit Feather M0 Express" - usb_STRING_MANUFACTURER = "Adafruit" -) - -var ( - usb_VID uint16 = 0x239A - usb_PID uint16 = 0x801B -) - -var ( - DefaultUART = UART0 -) diff --git a/emb/machine/board_feather-m0.go b/emb/machine/board_feather-m0.go deleted file mode 100644 index f38d8ec..0000000 --- a/emb/machine/board_feather-m0.go +++ /dev/null @@ -1,97 +0,0 @@ -//go:build sam && atsamd21 && feather_m0 - -package machine - -// used to reset into bootloader -const resetMagicValue = 0xf01669ef - -// GPIO Pins -const ( - D0 = PA11 // UART0 RX - D1 = PA10 // UART0 TX - D2 = NoPin // does not seem to exist - D3 = PA09 - D4 = PA08 - D5 = PA15 // PWM available - D6 = PA20 // PWM available - D7 = NoPin // does not seem to exist - D8 = PA06 - D9 = PA07 // PWM available - D10 = PA18 // can be used for PWM or UART1 TX - D11 = PA16 // can be used for PWM or UART1 RX - D12 = PA19 // PWM available - D13 = PA17 // PWM available -) - -// Analog pins -const ( - A0 = PA02 // ADC/AIN[0] - A1 = PB08 // ADC/AIN[2] - A2 = PB09 // ADC/AIN[3] - A3 = PA04 // ADC/AIN[4] - A4 = PA05 // ADC/AIN[5] - A5 = PB02 // ADC/AIN[10] -) - -const ( - LED = D13 -) - -// USBCDC pins -const ( - USBCDC_DM_PIN = PA24 - USBCDC_DP_PIN = PA25 -) - -// UART1 pins -const ( - UART_TX_PIN = D10 - UART_RX_PIN = D11 -) - -// UART1 on the Feather M0. -var UART1 = &sercomUSART1 - -// I2C pins -const ( - SDA_PIN = PA22 // SDA: SERCOM3/PAD[0] - SCL_PIN = PA23 // SCL: SERCOM3/PAD[1] -) - -// I2C on the Feather M0. -var ( - I2C0 = sercomI2CM3 -) - -// SPI pins -const ( - SPI0_SCK_PIN = PB11 // SCK: SERCOM4/PAD[3] - SPI0_SDO_PIN = PB10 // SDO: SERCOM4/PAD[2] - SPI0_SDI_PIN = PA12 // SDI: SERCOM4/PAD[0] -) - -// SPI on the Feather M0. -var SPI0 = sercomSPIM4 - -// I2S pins -const ( - I2S_SCK_PIN = PA10 - I2S_SDO_PIN = PA08 - I2S_SDI_PIN = NoPin - I2S_WS_PIN = NoPin // TODO: figure out what this is on Feather M0. -) - -// USB CDC identifiers -const ( - usb_STRING_PRODUCT = "Adafruit Feather M0 Express" - usb_STRING_MANUFACTURER = "Adafruit" -) - -var ( - usb_VID uint16 = 0x239A - usb_PID uint16 = 0x801B -) - -var ( - DefaultUART = UART1 -) diff --git a/emb/machine/board_feather-m4-can.go b/emb/machine/board_feather-m4-can.go deleted file mode 100644 index 6a39506..0000000 --- a/emb/machine/board_feather-m4-can.go +++ /dev/null @@ -1,138 +0,0 @@ -//go:build feather_m4_can - -package machine - -import ( - "device/sam" -) - -// used to reset into bootloader -const resetMagicValue = 0xf01669ef - -// GPIO Pins -const ( - D0 = PB17 // UART0 RX/PWM available - D1 = PB16 // UART0 TX/PWM available - D4 = PA14 // PWM available - D5 = PA16 // PWM available - D6 = PA18 // PWM available - D7 = PB03 // neopixel power - D8 = PB02 // built-in neopixel - D9 = PA19 // PWM available - D10 = PA20 // can be used for PWM or UART1 TX - D11 = PA21 // can be used for PWM or UART1 RX - D12 = PA22 // PWM available - D13 = PA23 // PWM available - D21 = PA13 // PWM available - D22 = PA12 // PWM available - D23 = PB22 // PWM available - D24 = PB23 // PWM available - D25 = PA17 // PWM available -) - -// Analog pins -const ( - A0 = PA02 // ADC/AIN[0] - A1 = PA05 // ADC/AIN[2] - A2 = PB08 // ADC/AIN[3] - A3 = PB09 // ADC/AIN[4] - A4 = PA04 // ADC/AIN[5] - A5 = PA06 // ADC/AIN[10] -) - -const ( - LED = D13 - NEOPIXELS = D8 - WS2812 = D8 -) - -// USBCDC pins -const ( - USBCDC_DM_PIN = PA24 - USBCDC_DP_PIN = PA25 -) - -const ( - UART_TX_PIN = D1 - UART_RX_PIN = D0 -) - -const ( - UART2_TX_PIN = A4 - UART2_RX_PIN = A5 -) - -// I2C pins -const ( - SDA_PIN = D22 // SDA: SERCOM2/PAD[0] - SCL_PIN = D21 // SCL: SERCOM2/PAD[1] -) - -// SPI pins -const ( - SPI0_SCK_PIN = D25 // SCK: SERCOM1/PAD[1] - SPI0_SDO_PIN = D24 // SDO: SERCOM1/PAD[3] - SPI0_SDI_PIN = D23 // SDI: SERCOM1/PAD[2] -) - -// CAN pins -const ( - CAN0_TX = PA22 - CAN0_RX = PA23 - - CAN1_STANDBY = PB12 - CAN1_TX = PB14 - CAN1_RX = PB15 - BOOST_EN = PB13 // power control of CAN1's TCAN1051HGV (H: enable) - - CAN_STANDBY = CAN1_STANDBY - CAN_S = CAN1_STANDBY - CAN_TX = CAN1_TX - CAN_RX = CAN1_RX -) - -// USB CDC identifiers -const ( - usb_STRING_PRODUCT = "Adafruit Feather M4 CAN" - usb_STRING_MANUFACTURER = "Adafruit" -) - -var ( - usb_VID uint16 = 0x239A - usb_PID uint16 = 0x80CD -) - -var ( - UART1 = &sercomUSART5 - - UART2 = &sercomUSART0 -) - -func init() { - // turn on neopixel - D7.Configure(PinConfig{Mode: PinOutput}) - D7.High() -} - -// I2C on the Feather M4 CAN. -var ( - I2C0 = sercomI2CM2 -) - -// SPI on the Feather M4 CAN. -var SPI0 = sercomSPIM1 - -// CAN on the Feather M4 CAN. -var ( - CAN0 = CAN{ - Bus: sam.CAN0, - } - - CAN1 = CAN{ - Bus: sam.CAN1, - } -) - -var ( - DefaultUART = UART1 -) diff --git a/emb/machine/board_feather-m4.go b/emb/machine/board_feather-m4.go deleted file mode 100644 index fb88fb9..0000000 --- a/emb/machine/board_feather-m4.go +++ /dev/null @@ -1,96 +0,0 @@ -//go:build feather_m4 - -package machine - -// used to reset into bootloader -const resetMagicValue = 0xf01669ef - -// GPIO Pins -const ( - D0 = PB17 // UART0 RX/PWM available - D1 = PB16 // UART0 TX/PWM available - D4 = PA14 // PWM available - D5 = PA16 // PWM available - D6 = PA18 // PWM available - D8 = PB03 // built-in neopixel - D9 = PA19 // PWM available - D10 = PA20 // can be used for PWM or UART1 TX - D11 = PA21 // can be used for PWM or UART1 RX - D12 = PA22 // PWM available - D13 = PA23 // PWM available - D21 = PA13 // PWM available - D22 = PA12 // PWM available - D23 = PB22 // PWM available - D24 = PB23 // PWM available - D25 = PA17 // PWM available -) - -// Analog pins -const ( - A0 = PA02 // ADC/AIN[0] - A1 = PA05 // ADC/AIN[2] - A2 = PB08 // ADC/AIN[3] - A3 = PB09 // ADC/AIN[4] - A4 = PA04 // ADC/AIN[5] - A5 = PA06 // ADC/AIN[10] -) - -const ( - LED = D13 - WS2812 = D8 -) - -// USBCDC pins -const ( - USBCDC_DM_PIN = PA24 - USBCDC_DP_PIN = PA25 -) - -const ( - UART_TX_PIN = D1 - UART_RX_PIN = D0 -) - -const ( - UART2_TX_PIN = A4 - UART2_RX_PIN = A5 -) - -var ( - UART1 = &sercomUSART5 - UART2 = &sercomUSART0 - - DefaultUART = UART1 -) - -// I2C pins -const ( - SDA_PIN = D22 // SDA: SERCOM2/PAD[0] - SCL_PIN = D21 // SCL: SERCOM2/PAD[1] -) - -// I2C on the Feather M4. -var ( - I2C0 = sercomI2CM2 -) - -// SPI pins -const ( - SPI0_SCK_PIN = D25 // SCK: SERCOM1/PAD[1] - SPI0_SDO_PIN = D24 // SDO: SERCOM1/PAD[3] - SPI0_SDI_PIN = D23 // SDI: SERCOM1/PAD[2] -) - -// SPI on the Feather M4. -var SPI0 = sercomSPIM1 - -// USB CDC identifiers -const ( - usb_STRING_PRODUCT = "Adafruit Feather M4" - usb_STRING_MANUFACTURER = "Adafruit" -) - -var ( - usb_VID uint16 = 0x239A - usb_PID uint16 = 0x8022 -) diff --git a/emb/machine/board_feather-nrf52840-sense.go b/emb/machine/board_feather-nrf52840-sense.go deleted file mode 100644 index ab1c3fb..0000000 --- a/emb/machine/board_feather-nrf52840-sense.go +++ /dev/null @@ -1,105 +0,0 @@ -//go:build feather_nrf52840_sense - -package machine - -const HasLowFrequencyCrystal = false - -// GPIO Pins -const ( - D0 = P0_25 // UART TX - D1 = P0_24 // UART RX - D2 = P0_10 // NFC2 - D3 = P1_11 - D4 = P1_10 // LED2 - D5 = P1_08 - D6 = P0_07 - D7 = P1_02 // Button - D8 = P0_16 // NeoPixel - D9 = P0_26 - D10 = P0_27 - D11 = P0_06 - D12 = P0_08 - D13 = P1_09 // LED1 - D14 = P0_04 // A0 - D15 = P0_05 // A1 - D16 = P0_30 // A2 - D17 = P0_28 // A3 - D18 = P0_02 // A4 - D19 = P0_03 // A5 - D20 = P0_29 // Battery - D21 = P0_31 // AREF - D22 = P0_12 // I2C SDA - D23 = P0_11 // I2C SCL - D24 = P0_15 // SPI MISO - D25 = P0_13 // SPI MOSI - D26 = P0_14 // SPI SCK - D27 = P0_19 // QSPI CLK - D28 = P0_20 // QSPI CS - D29 = P0_17 // QSPI Data 0 - D30 = P0_22 // QSPI Data 1 - D31 = P0_23 // QSPI Data 2 - D32 = P0_21 // QSPI Data 3 - D33 = P0_09 // NFC1 (test point on bottom of board) -) - -// Analog Pins -const ( - A0 = D14 - A1 = D15 - A2 = D16 - A3 = D17 - A4 = D18 - A5 = D19 - A6 = D20 // Battery - A7 = D21 // ARef -) - -const ( - LED = D13 - LED1 = LED - LED2 = D4 - NEOPIXEL = D8 - WS2812 = D8 - BUTTON = D7 - - QSPI_SCK = D27 - QSPI_CS = D28 - QSPI_DATA0 = D29 - QSPI_DATA1 = D30 - QSPI_DATA2 = D31 - QSPI_DATA3 = D32 -) - -// UART0 pins (logical UART1) -const ( - UART_RX_PIN = D1 - UART_TX_PIN = D0 -) - -// I2C pins -const ( - SDA_PIN = D22 // I2C0 external - SCL_PIN = D23 // I2C0 external -) - -// SPI pins -const ( - SPI0_SCK_PIN = D26 // SCK - SPI0_SDO_PIN = D25 // SDO - SPI0_SDI_PIN = D24 // SDI -) - -// USB CDC identifiers -const ( - usb_STRING_PRODUCT = "Feather nRF52840 Express" - usb_STRING_MANUFACTURER = "Adafruit Industries LLC" -) - -var ( - usb_VID uint16 = 0x239A - usb_PID uint16 = 0x8088 -) - -var ( - DefaultUART = UART0 -) diff --git a/emb/machine/board_feather-nrf52840.go b/emb/machine/board_feather-nrf52840.go deleted file mode 100644 index 02fd053..0000000 --- a/emb/machine/board_feather-nrf52840.go +++ /dev/null @@ -1,105 +0,0 @@ -//go:build feather_nrf52840 - -package machine - -const HasLowFrequencyCrystal = true - -// GPIO Pins -const ( - D0 = P0_25 // UART TX - D1 = P0_24 // UART RX - D2 = P0_10 // NFC2 - D3 = P1_15 // LED1 - D4 = P1_10 // LED2 - D5 = P1_08 - D6 = P0_07 - D7 = P1_02 // Button - D8 = P0_16 // NeoPixel - D9 = P0_26 - D10 = P0_27 - D11 = P0_06 - D12 = P0_08 - D13 = P1_09 - D14 = P0_04 // A0 - D15 = P0_05 // A1 - D16 = P0_30 // A2 - D17 = P0_28 // A3 - D18 = P0_02 // A4 - D19 = P0_03 // A5 - D20 = P0_29 // Battery - D21 = P0_31 // AREF - D22 = P0_12 // I2C SDA - D23 = P0_11 // I2C SCL - D24 = P0_15 // SPI MISO - D25 = P0_13 // SPI MOSI - D26 = P0_14 // SPI SCK - D27 = P0_19 // QSPI CLK - D28 = P0_20 // QSPI CS - D29 = P0_17 // QSPI Data 0 - D30 = P0_22 // QSPI Data 1 - D31 = P0_23 // QSPI Data 2 - D32 = P0_21 // QSPI Data 3 - D33 = P0_09 // NFC1 (test point on bottom of board) -) - -// Analog Pins -const ( - A0 = D14 - A1 = D15 - A2 = D16 - A3 = D17 - A4 = D18 - A5 = D19 - A6 = D20 // Battery - A7 = D21 // ARef -) - -const ( - LED = D3 - LED1 = LED - LED2 = D4 - NEOPIXEL = D8 - WS2812 = D8 - BUTTON = D7 - - QSPI_SCK = D27 - QSPI_CS = D28 - QSPI_DATA0 = D29 - QSPI_DATA1 = D30 - QSPI_DATA2 = D31 - QSPI_DATA3 = D32 -) - -// UART0 pins (logical UART1) -const ( - UART_RX_PIN = D1 - UART_TX_PIN = D0 -) - -// I2C pins -const ( - SDA_PIN = D22 // I2C0 external - SCL_PIN = D23 // I2C0 external -) - -// SPI pins -const ( - SPI0_SCK_PIN = D26 // SCK - SPI0_SDO_PIN = D25 // SDO - SPI0_SDI_PIN = D24 // SDI -) - -// USB CDC identifiers -const ( - usb_STRING_PRODUCT = "Feather nRF52840 Express" - usb_STRING_MANUFACTURER = "Adafruit Industries LLC" -) - -var ( - usb_VID uint16 = 0x239A - usb_PID uint16 = 0x802A -) - -var ( - DefaultUART = UART0 -) diff --git a/emb/machine/board_feather-stm32f405.go b/emb/machine/board_feather-stm32f405.go deleted file mode 100644 index 4a184ba..0000000 --- a/emb/machine/board_feather-stm32f405.go +++ /dev/null @@ -1,255 +0,0 @@ -//go:build feather_stm32f405 - -package machine - -import ( - "device/stm32" - "runtime/interrupt" -) - -const ( - NUM_DIGITAL_IO_PINS = 39 - NUM_ANALOG_IO_PINS = 7 -) - -// Digital pins -const ( - // Arduino pin = MCU port pin // primary functions (alternate functions) - D0 = PB11 // USART3 RX, PWM TIM2_CH4 (I2C2 SDA) - D1 = PB10 // USART3 TX, PWM TIM2_CH3 (I2C2 SCL, I2S2 BCK) - D2 = PB3 // GPIO, SPI3 FLASH SCK - D3 = PB4 // GPIO, SPI3 FLASH MISO - D4 = PB5 // GPIO, SPI3 FLASH MOSI - D5 = PC7 // GPIO, PWM TIM3_CH2 (USART6 RX, I2S3 MCK) - D6 = PC6 // GPIO, PWM TIM3_CH1 (USART6 TX, I2S2 MCK) - D7 = PA15 // GPIO, SPI3 FLASH CS - D8 = PC0 // GPIO, Neopixel - D9 = PB8 // GPIO, PWM TIM4_CH3 (CAN1 RX, I2C1 SCL) - D10 = PB9 // GPIO, PWM TIM4_CH4 (CAN1 TX, I2C1 SDA, I2S2 WSL) - D11 = PC3 // GPIO (I2S2 SD, SPI2 MOSI) - D12 = PC2 // GPIO (I2S2ext SD, SPI2 MISO) - D13 = PC1 // GPIO, Builtin LED - D14 = PB7 // I2C1 SDA, PWM TIM4_CH2 (USART1 RX) - D15 = PB6 // I2C1 SCL, PWM TIM4_CH1 (USART1 TX, CAN2 TX) - D16 = PA4 // A0 (DAC OUT1) - D17 = PA5 // A1 (DAC OUT2, SPI1 SCK) - D18 = PA6 // A2, PWM TIM3_CH1 (SPI1 MISO) - D19 = PA7 // A3, PWM TIM3_CH2 (SPI1 MOSI) - D20 = PC4 // A4 - D21 = PC5 // A5 - D22 = PA3 // A6 - D23 = PB13 // SPI2 SCK, PWM TIM1_CH1N (I2S2 BCK, CAN2 TX) - D24 = PB14 // SPI2 MISO, PWM TIM1_CH2N (I2S2ext SD) - D25 = PB15 // SPI2 MOSI, PWM TIM1_CH3N (I2S2 SD) - D26 = PC8 // SDIO - D27 = PC9 // SDIO - D28 = PC10 // SDIO - D29 = PC11 // SDIO - D30 = PC12 // SDIO - D31 = PD2 // SDIO - D32 = PB12 // SD Detect - D33 = PC14 // OSC32 - D34 = PC15 // OSC32 - D35 = PA11 // USB D+ - D36 = PA12 // USB D- - D37 = PA13 // SWDIO - D38 = PA14 // SWCLK -) - -// Analog pins -const ( - A0 = D16 // ADC12 IN4 - A1 = D17 // ADC12 IN5 - A2 = D18 // ADC12 IN6 - A3 = D19 // ADC12 IN7 - A4 = D20 // ADC12 IN14 - A5 = D21 // ADC12 IN15 - A6 = D22 // VBAT -) - -func init() { - initLED() - initUART() - initSPI() - initI2C() -} - -// -- LEDs --------------------------------------------------------------------- - -const ( - NUM_BOARD_LED = 1 - NUM_BOARD_NEOPIXEL = 1 - - LED_RED = D13 - LED_NEOPIXEL = D8 - LED_BUILTIN = LED_RED - LED = LED_BUILTIN - WS2812 = D8 -) - -func initLED() {} - -// -- UART --------------------------------------------------------------------- - -const ( - // #===========#==========#==============#============#=======#=======# - // | Interface | Hardware | Bus(Freq) | RX/TX Pins | AltFn | Alias | - // #===========#==========#==============#============#=======#=======# - // | UART1 | USART3 | APB1(42 MHz) | D0/D1 | 7 | ~ | - // | UART2 | USART6 | APB2(84 MHz) | D5/D6 | 8 | ~ | - // | UART3 | USART1 | APB2(84 MHz) | D14/D15 | 7 | ~ | - // | --------- | -------- | ------------ | ---------- | ----- | ----- | - // | UART0 | USART3 | APB1(42 MHz) | D0/D1 | 7 | UART1 | - // #===========#==========#==============#============#=======#=======# - NUM_UART_INTERFACES = 3 - - UART1_RX_PIN = D0 // UART1 = hardware: USART3 - UART1_TX_PIN = D1 // - - UART2_RX_PIN = D5 // UART2 = hardware: USART6 - UART2_TX_PIN = D6 // - - UART3_RX_PIN = D14 // UART3 = hardware: USART1 - UART3_TX_PIN = D15 // - - UART0_RX_PIN = UART1_RX_PIN // UART0 = alias: UART1 - UART0_TX_PIN = UART1_TX_PIN // - - UART_RX_PIN = UART0_RX_PIN // default/primary UART pins - UART_TX_PIN = UART0_TX_PIN // -) - -var ( - UART1 = &_UART1 - _UART1 = UART{ - Buffer: NewRingBuffer(), - Bus: stm32.USART3, - TxAltFuncSelector: AF7_USART1_2_3, - RxAltFuncSelector: AF7_USART1_2_3, - } - UART2 = &_UART2 - _UART2 = UART{ - Buffer: NewRingBuffer(), - Bus: stm32.USART6, - TxAltFuncSelector: AF8_USART4_5_6, - RxAltFuncSelector: AF8_USART4_5_6, - } - UART3 = &_UART3 - _UART3 = UART{ - Buffer: NewRingBuffer(), - Bus: stm32.USART1, - TxAltFuncSelector: AF7_USART1_2_3, - RxAltFuncSelector: AF7_USART1_2_3, - } - DefaultUART = UART1 -) - -func initUART() { - UART1.Interrupt = interrupt.New(stm32.IRQ_USART3, _UART1.handleInterrupt) - UART2.Interrupt = interrupt.New(stm32.IRQ_USART6, _UART2.handleInterrupt) - UART3.Interrupt = interrupt.New(stm32.IRQ_USART1, _UART3.handleInterrupt) -} - -// -- SPI ---------------------------------------------------------------------- - -const ( - // #===========#==========#==============#==================#=======#=======# - // | Interface | Hardware | Bus(Freq) | SCK/SDI/SDO Pins | AltFn | Alias | - // #===========#==========#==============#==================#=======#=======# - // | SPI1 | SPI2 | APB1(42 MHz) | D23/D24/D25 | 5 | ~ | - // | SPI2 | SPI3 | APB1(42 MHz) | D2/D3/D4 | 6 | ~ | - // | SPI3 | SPI1 | APB2(84 MHz) | D17/D18/D19 | 5 | ~ | - // | --------- | -------- | ------------ | ---------------- | ----- | ----- | - // | SPI0 | SPI2 | APB1(42 MHz) | D23/D24/D25 | 5 | SPI1 | - // #===========#==========#==============#==================#=======#=======# - NUM_SPI_INTERFACES = 3 - - SPI1_SCK_PIN = D23 // - SPI1_SDI_PIN = D24 // SPI1 = hardware: SPI2 - SPI1_SDO_PIN = D25 // - - SPI2_SCK_PIN = D2 // - SPI2_SDI_PIN = D3 // SPI2 = hardware: SPI3 - SPI2_SDO_PIN = D4 // - - SPI3_SCK_PIN = D17 // - SPI3_SDI_PIN = D18 // SPI3 = hardware: SPI1 - SPI3_SDO_PIN = D19 // - - SPI0_SCK_PIN = SPI1_SCK_PIN // - SPI0_SDI_PIN = SPI1_SDI_PIN // SPI0 = alias: SPI1 - SPI0_SDO_PIN = SPI1_SDO_PIN // - - SPI_SCK_PIN = SPI0_SCK_PIN // - SPI_SDI_PIN = SPI0_SDI_PIN // default/primary SPI pins - SPI_SDO_PIN = SPI0_SDO_PIN // -) - -var ( - SPI1 = &SPI{ - Bus: stm32.SPI2, - AltFuncSelector: AF5_SPI1_SPI2, - } - SPI2 = &SPI{ - Bus: stm32.SPI3, - AltFuncSelector: AF6_SPI3, - } - SPI3 = &SPI{ - Bus: stm32.SPI1, - AltFuncSelector: AF5_SPI1_SPI2, - } - SPI0 = SPI1 -) - -func initSPI() {} - -// -- I2C ---------------------------------------------------------------------- - -const ( - // #===========#==========#==============#==============#=======#=======# - // | Interface | Hardware | Bus(Freq) | SDA/SCL Pins | AltFn | Alias | - // #===========#==========#==============#==============#=======#=======# - // | I2C1 | I2C1 | APB1(42 MHz) | D14/D15 | 4 | ~ | - // | I2C2 | I2C2 | APB1(42 MHz) | D0/D1 | 4 | ~ | - // | I2C3 | I2C1 | APB1(42 MHz) | D9/D10 | 4 | ~ | - // | --------- | -------- | ------------ | ------------ | ----- | ----- | - // | I2C0 | I2C1 | APB1(42 MHz) | D14/D15 | 4 | I2C1 | - // #===========#==========#==============#==============#=======#=======# - NUM_I2C_INTERFACES = 3 - - I2C1_SDA_PIN = D14 // I2C1 = hardware: I2C1 - I2C1_SCL_PIN = D15 // - - I2C2_SDA_PIN = D0 // I2C2 = hardware: I2C2 - I2C2_SCL_PIN = D1 // - - I2C3_SDA_PIN = D9 // I2C3 = hardware: I2C1 - I2C3_SCL_PIN = D10 // (interface duplicated on second pair of pins) - - I2C0_SDA_PIN = I2C1_SDA_PIN // I2C0 = alias: I2C1 - I2C0_SCL_PIN = I2C1_SCL_PIN // - - I2C_SDA_PIN = I2C0_SDA_PIN // default/primary I2C pins - I2C_SCL_PIN = I2C0_SCL_PIN // - - SDA_PIN = I2C0_SDA_PIN - SCL_PIN = I2C0_SCL_PIN -) - -var ( - I2C1 = &I2C{ - Bus: stm32.I2C1, - AltFuncSelector: AF4_I2C1_2_3, - } - I2C2 = &I2C{ - Bus: stm32.I2C2, - AltFuncSelector: AF4_I2C1_2_3, - } - I2C3 = &I2C{ - Bus: stm32.I2C1, - AltFuncSelector: AF4_I2C1_2_3, - } - I2C0 = I2C1 -) - -func initI2C() {} diff --git a/emb/machine/board_feather_rp2040.go b/emb/machine/board_feather_rp2040.go deleted file mode 100644 index 44091e5..0000000 --- a/emb/machine/board_feather_rp2040.go +++ /dev/null @@ -1,82 +0,0 @@ -//go:build feather_rp2040 - -package machine - -// Onboard crystal oscillator frequency, in MHz. -const xoscFreq = 12 // MHz - -// GPIO Pins -const ( - D4 = GPIO6 - D5 = GPIO7 - D6 = GPIO8 - D9 = GPIO9 - D10 = GPIO10 - D11 = GPIO11 - D12 = GPIO12 - D13 = GPIO13 - D24 = GPIO24 - D25 = GPIO25 -) - -// Analog pins -const ( - A0 = GPIO26 - A1 = GPIO27 - A2 = GPIO28 - A3 = GPIO29 -) - -const LED = GPIO13 - -// I2C Pins. -const ( - I2C0_SDA_PIN = GPIO24 - I2C0_SCL_PIN = GPIO25 - - I2C1_SDA_PIN = GPIO2 - I2C1_SCL_PIN = GPIO3 - - SDA_PIN = I2C1_SDA_PIN - SCL_PIN = I2C1_SCL_PIN -) - -// SPI default pins -const ( - // Default Serial Clock Bus 0 for SPI communications - SPI0_SCK_PIN = GPIO18 - // Default Serial Out Bus 0 for SPI communications - SPI0_SDO_PIN = GPIO19 // Tx - // Default Serial In Bus 0 for SPI communications - SPI0_SDI_PIN = GPIO20 // Rx - - // Default Serial Clock Bus 1 for SPI communications - SPI1_SCK_PIN = GPIO10 - // Default Serial Out Bus 1 for SPI communications - SPI1_SDO_PIN = GPIO11 // Tx - // Default Serial In Bus 1 for SPI communications - SPI1_SDI_PIN = GPIO12 // Rx -) - -// UART pins -const ( - UART0_TX_PIN = GPIO0 - UART0_RX_PIN = GPIO1 - UART1_TX_PIN = GPIO8 - UART1_RX_PIN = GPIO9 - UART_TX_PIN = UART0_TX_PIN - UART_RX_PIN = UART0_RX_PIN -) - -var DefaultUART = UART0 - -// USB identifiers -const ( - usb_STRING_PRODUCT = "Feather RP2040" - usb_STRING_MANUFACTURER = "Adafruit" -) - -var ( - usb_VID uint16 = 0x239A - usb_PID uint16 = 0x80F1 -) diff --git a/emb/machine/board_gemma-m0.go b/emb/machine/board_gemma-m0.go deleted file mode 100644 index af1caaa..0000000 --- a/emb/machine/board_gemma-m0.go +++ /dev/null @@ -1,97 +0,0 @@ -//go:build sam && atsamd21 && gemma_m0 - -package machine - -// Used to reset into bootloader. -const resetMagicValue = 0xf01669ef - -// GPIO Pins. -const ( - D0 = PA04 // SERCOM0/PAD[0] - D1 = PA02 - D2 = PA05 // SERCOM0/PAD[1] - D3 = PA00 // DotStar LED: SERCOM1/PAD[0]: APA102/MOSI - D4 = PA01 // DotStar LED: SERCOM1/PAD[1]: APA102/SCK - D11 = PA30 // Flash Access: SERCOM1/PAD[2] - D12 = PA31 // Flash Access: SERCOM1/PAD[3] - D13 = PA23 // LED: SERCOM3/PAD[1] SERCOM5/PAD[1] -) - -// Analog pins. -const ( - A0 = D1 - A1 = D2 - A2 = D0 -) - -const ( - LED = PA23 -) - -// USBCDC pins. -const ( - USBCDC_DM_PIN = PA24 - USBCDC_DP_PIN = PA25 -) - -// UART0 pins. -const ( - UART_TX_PIN = PA04 // TX: SERCOM0/PAD[0] - UART_RX_PIN = PA05 // RX: SERCOM0/PAD[1] -) - -// UART0s on the Gemma M0. -var UART0 = &sercomUSART0 - -// SPI pins. -const ( - SPI0_SCK_PIN = PA05 // SCK: SERCOM0/PAD[1] - SPI0_SDO_PIN = PA04 // MOSI: SERCOM0/PAD[0] - SPI0_SDI_PIN = NoPin - SPI0_CS_PIN = NoPin -) - -// SPI on the Gemma M0. -var SPI0 = sercomSPIM0 - -// SPI pins for DotStar LED (using APA102 software SPI) and Flash. -const ( - SPI1_SCK_PIN = PA01 // SCK: SERCOM1/PAD[0] - SPI1_SDO_PIN = PA00 // MOSI: SERCOM1/PAD[1] - SPI1_SDI_PIN = PA31 // MISO: SERCOM1/PAD[3] - SPI1_CS_PIN = PA30 // CS: SERCOM1/PAD[2] -) - -// I2C pins. -const ( - SDA_PIN = PA04 // SDA: SERCOM0/PAD[0] - SCL_PIN = PA05 // SCL: SERCOM0/PAD[1] -) - -// I2C on the Gemma M0. -var ( - I2C0 = sercomI2CM0 -) - -// I2S (not connected, needed for atsamd21). -const ( - I2S_SCK_PIN = NoPin - I2S_SDO_PIN = NoPin - I2S_SDI_PIN = NoPin - I2S_WS_PIN = NoPin -) - -// USB CDC identifiers. -const ( - usb_STRING_PRODUCT = "Adafruit Gemma M0" - usb_STRING_MANUFACTURER = "Adafruit" -) - -var ( - usb_VID uint16 = 0x239A - usb_PID uint16 = 0x801E -) - -var ( - DefaultUART = UART0 -) diff --git a/emb/machine/board_gnse.go b/emb/machine/board_gnse.go deleted file mode 100644 index 8e78b43..0000000 --- a/emb/machine/board_gnse.go +++ /dev/null @@ -1,88 +0,0 @@ -//go:build gnse - -package machine - -import ( - "device/stm32" - "runtime/interrupt" -) - -const ( - LED_RED = PB5 - LED_GREEN = PB6 - LED_BLUE = PB7 - LED1 = LED_RED // Red - LED2 = LED_GREEN // Green - LED3 = LED_BLUE // Blue - LED = LED_GREEN // Default - - BUTTON = PB3 - BUZZER = PA15 - VBATT_ADC = PB2 - SENSOR_EN = PB12 - FLASH_EN = PC13 - - // SPI0 - SPI0_NSS_PIN = PA4 - SPI0_SCK_PIN = PA5 - SPI0_SDO_PIN = PA6 - SPI0_SDI_PIN = PA7 - - //MCU USART2 - UART2_RX_PIN = PA3 - UART2_TX_PIN = PA2 - - // DEFAULT USART - UART_RX_PIN = UART2_RX_PIN - UART_TX_PIN = UART2_TX_PIN - - // I2C1 pins - // I2C1 is connected to Flash, Accelerometer, Env. Sensor, Crypto Element) - I2C1_SCL_PIN = PA9 - I2C1_SDA_PIN = PA10 - I2C1_ALT_FUNC = 4 - - // I2C2 pins - // I2C2 is expansion J10 QWIIC Connector - I2C2_SCL_PIN = PA12 - I2C2_SDA_PIN = PA11 - I2C2_ALT_FUNC = 4 - - // I2C0 alias for I2C1 - I2C0_SDA_PIN = I2C1_SDA_PIN - I2C0_SCL_PIN = I2C1_SCL_PIN -) - -var ( - // STM32 UART2 is connected to the embedded STLINKV3 Virtual Com Port - UART0 = &_UART0 - _UART0 = UART{ - Buffer: NewRingBuffer(), - Bus: stm32.USART2, - TxAltFuncSelector: 7, - RxAltFuncSelector: 7, - } - - DefaultUART = UART0 - - // I2C Busses - I2C1 = &I2C{ - Bus: stm32.I2C1, - AltFuncSelector: I2C1_ALT_FUNC, - } - I2C2 = &I2C{ - Bus: stm32.I2C2, - AltFuncSelector: I2C2_ALT_FUNC, - } - I2C0 = I2C1 - - // SPI - SPI3 = &SPI{ - Bus: stm32.SPI3, - } -) - -func init() { - // Enable UARTs Interrupts - UART0.Interrupt = interrupt.New(stm32.IRQ_USART2, _UART0.handleInterrupt) -} diff --git a/emb/machine/board_gopher-badge.go b/emb/machine/board_gopher-badge.go deleted file mode 100644 index 7af2711..0000000 --- a/emb/machine/board_gopher-badge.go +++ /dev/null @@ -1,90 +0,0 @@ -//go:build gopher_badge - -// This contains the pin mappings for the Gopher Badge. -// -// For more information, see: https://gopherbadge.com/ -package machine - -const ( - /*ADC0 Pin = GPIO26 - ADC1 Pin = GPIO27 - ADC2 Pin = GPIO28 - GPIO4 Pin = GPIO4 - GPIO5 Pin = GPIO5 - GPIO6 Pin = GPIO6 - GPIO7 Pin = GPIO7 - GPIO8 Pin = GPIO8 - GPIO9 Pin = GPIO9*/ - - PENIRQ Pin = GPIO13 - - LED Pin = GPIO2 - NEOPIXELS Pin = GPIO15 - WS2812 Pin = GPIO15 - - BUTTON_A Pin = GPIO10 - BUTTON_B Pin = GPIO11 - BUTTON_LEFT Pin = GPIO25 - BUTTON_UP Pin = GPIO24 - BUTTON_RIGHT Pin = GPIO22 - BUTTON_DOWN Pin = GPIO23 - - TFT_RST Pin = GPIO21 - TFT_SDI Pin = GPIO19 - TFT_SDO Pin = GPIO16 - TFT_CS Pin = GPIO17 - TFT_SCL Pin = GPIO18 - TFT_WRX Pin = GPIO20 - TFT_BACKLIGHT Pin = GPIO12 - - SPEAKER Pin = GPIO14 - SPEAKER_ENABLE Pin = GPIO3 -) - -// I2C pins -const ( - I2C0_SDA_PIN Pin = GPIO0 - I2C0_SCL_PIN Pin = GPIO1 - - I2C1_SDA_PIN Pin = NoPin - I2C1_SCL_PIN Pin = NoPin -) - -// SPI pins. -const ( - SPI0_SCK_PIN Pin = GPIO18 - SPI0_SDO_PIN Pin = GPIO19 - SPI0_SDI_PIN Pin = GPIO16 - - SPI1_SCK_PIN Pin = NoPin - SPI1_SDO_PIN Pin = NoPin - SPI1_SDI_PIN Pin = NoPin -) - -// Onboard crystal oscillator frequency, in MHz. -const ( - xoscFreq = 12 // MHz -) - -// USB CDC identifiers -const ( - usb_STRING_PRODUCT = "Gopher Badge" - usb_STRING_MANUFACTURER = "TinyGo" -) - -var ( - usb_VID uint16 = 0x2e8a - usb_PID uint16 = 0x0003 -) - -// UART pins -const ( - UART0_TX_PIN = GPIO0 - UART0_RX_PIN = GPIO1 - UART1_TX_PIN = GPIO4 - UART1_RX_PIN = GPIO5 - UART_TX_PIN = UART0_TX_PIN - UART_RX_PIN = UART0_RX_PIN -) - -var DefaultUART = UART1 diff --git a/emb/machine/board_grandcentral-m4.go b/emb/machine/board_grandcentral-m4.go deleted file mode 100644 index 61ef6a8..0000000 --- a/emb/machine/board_grandcentral-m4.go +++ /dev/null @@ -1,267 +0,0 @@ -//go:build grandcentral_m4 - -package machine - -// Digital pins -const ( - // = Pin Alt. Function SERCOM PWM Timer Interrupt - // ------ -------------------- -------- ----------- ----------- - D0 = PB25 // UART1 RX 0[1] EXTI9 - D1 = PB24 // UART1 TX 0[0] EXTI8 - D2 = PC18 // TCC0[2] EXTI2 - D3 = PC19 // TCC0[3] EXTI3 - D4 = PC20 // TCC0[4] EXTI4 - D5 = PC21 // TCC0[5] EXTI5 - D6 = PD20 // TCC1[0] EXTI10 - D7 = PD21 // TCC1[1] EXTI11 - D8 = PB18 // TCC1[0] EXTI2 - D9 = PB02 // TC6[0] EXTI3 - D10 = PB22 // TC7[0] EXTI6 - D11 = PB23 // EXTI7 - D12 = PB00 // TC7[0] EXTI0 - D13 = PB01 // On-board LED TC7[1] EXTI1 - D14 = PB16 // UART4 TX, I2S0 SCK 5[0] TC6[0] EXTI0 - D15 = PB17 // UART4 RX, I2S0 MCK 5[1] EXTI1 - D16 = PC22 // UART3 TX 1[0] EXTI6 - D17 = PC23 // UART3 RX 1[1] EXTI6 - D18 = PB12 // UART2 TX 4[0] TCC3[0] EXTI12 - D19 = PB13 // UART2 RX 4[1] TCC3[1] EXTI13 - D20 = PB20 // I2C0 SDA 3[0] EXTI4 - D21 = PB21 // I2C0 SCL 3[1] EXTI5 - D22 = PD12 // EXTI7 - D23 = PA15 // TCC2[1] EXTI15 - D24 = PC17 // I2C1 SCL 6[1] TCC0[1] EXTI1 - D25 = PC16 // I2C1 SDA 6[0] TCC0[0] EXTI0 - D26 = PA12 // PCC DEN1 TC2[0] EXTI12 - D27 = PA13 // PCC DEN2 TC2[1] EXTI13 - D28 = PA14 // PCC CLK TCC2[0] EXTI14 - D29 = PB19 // PCC XCLK EXTI3 - D30 = PA23 // PCC D7 TC4[1] EXTI7 - D31 = PA22 // PCC D6, I2S0 SDI TC4[0] EXTI6 - D32 = PA21 // PCC D5, I2S0 SDO EXTI5 - D33 = PA20 // PCC D4, I2S0 FS EXTI4 - D34 = PA19 // PCC D3 TC3[1] EXTI3 - D35 = PA18 // PCC D2 TC3[0] EXTI2 - D36 = PA17 // PCC D1 EXTI1 - D37 = PA16 // PCC D0 EXTI0 - D38 = PB15 // PCC D9 TCC4[1] EXTI15 - D39 = PB14 // PCC D8 TCC4[0] EXTI14 - D40 = PC13 // PCC D11 EXTI13 - D41 = PC12 // PCC D10 EXTI12 - D42 = PC15 // PCC D13 EXTI15 - D43 = PC14 // PCC D12 EXTI14 - D44 = PC11 // EXTI11 - D45 = PC10 // EXTI10 - D46 = PC06 // EXTI6 - D47 = PC07 // EXTI5 - D48 = PC04 // EXTI4 - D49 = PC05 // EXTI5 - D50 = PD11 // SPI0 SDI 7[3] EXTI11 - D51 = PD08 // SPI0 SDO 7[0] EXTI8 - D52 = PD09 // SPI0 SCK 7[1] EXTI9 - D53 = PD10 // SPI0 CS EXTI10 - D54 = PB05 // ADC1 (A8) EXTI5 - D55 = PB06 // ADC1 (A9) EXTI6 - D56 = PB07 // ADC1 (A10) EXTI7 - D57 = PB08 // ADC1 (A11) EXTI8 - D58 = PB09 // ADC1 (A12) EXTI9 - D59 = PA04 // ADC0 (A13) TC0[0] EXTI4 - D60 = PA06 // ADC0 (A14) TC1[0] EXTI6 - D61 = PA07 // ADC0 (A15) TC1[1] EXTI7 - D62 = PB20 // I2C0 SDA 3[0] TCC1[2] EXTI4 - D63 = PB21 // I2C0 SCL 3[1] TCC1[3] EXTI5 - D64 = PD11 // SPI0 SDI 7[3] EXTI6 - D65 = PD08 // SPI0 SDO 7[0] EXTI3 - D66 = PD09 // SPI0 SCK 7[1] EXTI4 - D67 = PA02 // ADC0 (A0), DAC0 EXTI2 - D68 = PA05 // ADC0 (A1), DAC1 EXTI5 - D69 = PB03 // ADC0 (A2) TC6[1] EXTI3 - D70 = PC00 // ADC1 (A3) EXTI0 - D71 = PC01 // ADC1 (A4) EXTI1 - D72 = PC02 // ADC1 (A5) EXTI2 - D73 = PC03 // ADC1 (A6) EXTI3 - D74 = PB04 // ADC1 (A7) EXTI4 - D75 = PC31 // UART RX LED - D76 = PC30 // UART TX LED - D77 = PA27 // USB HOST EN - D78 = PA24 // USB DM EXTI8 - D79 = PA25 // USB DP EXTI9 - D80 = PB29 // SD/SPI1 SDI 2[3] - D81 = PB27 // SD/SPI1 SCK 2[1] - D82 = PB26 // SD/SPI1 SDO 2[0] - D83 = PB28 // SD/SPI1 CS - D84 = PA03 // AREF EXTI3 - D85 = PA02 // DAC0 EXTI2 - D86 = PA05 // DAC1 EXTI5 - D87 = PB01 // On-board LED (D13) TC7[1] EXTI1 - D88 = PC24 // On-board NeoPixel - D89 = PB10 // QSPI SCK EXTI10 - D90 = PB11 // QSPI CS EXTI11 - D91 = PA08 // QSPI ID0 EXTI(NMI) - D92 = PA09 // QSPI ID1 EXTI9 - D93 = PA10 // QSPI ID2 EXTI10 - D94 = PA11 // QSPI ID3 EXTI11 - D95 = PB31 // SD Detect EXTI15 - D96 = PB30 // SWO EXTI14 -) - -// Analog pins -const ( - A0 = D67 // (PA02) ADC0 ch. 0, - A1 = D68 // (PA05) ADC0 ch. 5, - A2 = D69 // (PB03) ADC0 ch. 15 - A3 = D70 // (PC00) ADC1 ch. 10 - A4 = D71 // (PC01) ADC1 ch. 11 - A5 = D72 // (PC02) ADC1 ch. 4 - A6 = D73 // (PC03) ADC1 ch. 5 - A7 = D74 // (PB04) ADC1 ch. 6 - A8 = D54 // (PB05) ADC1 ch. 7 - A9 = D55 // (PB06) ADC1 ch. 8 - A10 = D56 // (PB07) ADC1 ch. 9 - A11 = D57 // (PB08) ADC1 ch. 0 - A12 = D58 // (PB09) ADC1 ch. 1 - A13 = D59 // (PA04) ADC0 ch. 4 - A14 = D60 // (PA06) ADC0 ch. 6 - A15 = D61 // (PA07) ADC0 ch. 7 - - AREF = D84 // (PA03) -) - -// LED pins -const ( - LED_PIN = D13 // (PB01), also on D87 - UART_RX_LED_PIN = D75 // (PC31) - UART_TX_LED_PIN = D76 // (PC30) - NEOPIXEL_PIN = D88 // (PC24) - - // aliases used by examples and drivers - LED = LED_PIN - LED_RX = UART_RX_LED_PIN - LED_TX = UART_TX_LED_PIN - NEOPIXEL = NEOPIXEL_PIN - WS2812 = NEOPIXEL_PIN -) - -// UART pins -const ( - UART1_RX_PIN = D0 // (PB25) - UART1_TX_PIN = D1 // (PB24) - - UART2_RX_PIN = D19 // (PB13) - UART2_TX_PIN = D18 // (PB12) - - UART3_RX_PIN = D17 // (PC23) - UART3_TX_PIN = D16 // (PC22) - - UART4_RX_PIN = D15 // (PB17) - UART4_TX_PIN = D14 // (PB16) - - UART_RX_PIN = UART1_RX_PIN // default pins - UART_TX_PIN = UART1_TX_PIN // -) - -// UART on the Grand Central M4 -var ( - UART1 = &sercomUSART0 - UART2 = &sercomUSART4 - UART3 = &sercomUSART1 - UART4 = &sercomUSART5 - - DefaultUART = UART1 -) - -// SPI pins -const ( - SPI0_SCK_PIN = D66 // (PD09), also on D52 - SPI0_SDO_PIN = D65 // (PD08), also on D51 - SPI0_SDI_PIN = D64 // (PD11), also on D50 - SPI0_CS_PIN = D53 // (PD10) - - SPI1_SCK_PIN = D81 // (PB27) - SPI1_SDO_PIN = D82 // (PB26) - SPI1_SDI_PIN = D80 // (PB29) - - SPI_SCK_PIN = SPI0_SCK_PIN // default pins - SPI_SDO_PIN = SPI0_SDO_PIN // - SPI_SDI_PIN = SPI0_SDI_PIN // - SPI_CS_PIN = SPI0_CS_PIN // -) - -// SPI on the Grand Central M4 -var ( - SPI0 = sercomSPIM7 - SPI1 = sercomSPIM2 // SD card -) - -// I2C pins -const ( - I2C0_SDA_PIN = D62 // (PB20), also on D20 - I2C0_SCL_PIN = D63 // (PB21), also on D21 - - I2C1_SDA_PIN = D25 // (PC16) - I2C1_SCL_PIN = D24 // (PC17) - - I2C_SDA_PIN = I2C0_SDA_PIN // default pins - I2C_SCL_PIN = I2C0_SCL_PIN // - - SDA_PIN = I2C_SDA_PIN // unconventional pin names - SCL_PIN = I2C_SCL_PIN // (required by machine_atsamd51.go) -) - -// I2C on the Grand Central M4 -var ( - I2C0 = sercomI2CM3 - I2C1 = sercomI2CM6 -) - -// I2S pins -const ( - I2S0_SCK_PIN = D14 // (PB16) - I2S0_MCK_PIN = D15 // (PB17) - I2S0_FS_PIN = D33 // (PA20) - I2S0_SDO_PIN = D32 // (PA21) - I2S0_SDI_PIN = D31 // (PA22) - - I2S_SCK_PIN = I2S0_SCK_PIN // default pins - I2S_WS_PIN = I2S0_FS_PIN // - I2S_SDO_PIN = I2S0_SDO_PIN - I2S_SDI_PIN = NoPin -) - -// SD card pins -const ( - SD0_SCK_PIN = D81 // (PB27) - SD0_SDO_PIN = D82 // (PB26) - SD0_SDI_PIN = D80 // (PB29) - SD0_CS_PIN = D83 // (PB28) - SD0_DET_PIN = D95 // (PB31) - - SDCARD_SCK_PIN = SD0_SCK_PIN // default pins - SDCARD_SDO_PIN = SD0_SDO_PIN // - SDCARD_SDI_PIN = SD0_SDI_PIN // - SDCARD_CS_PIN = SD0_CS_PIN // - SDCARD_DET_PIN = SD0_DET_PIN // -) - -// Other peripheral constants -const ( - resetMagicValue = 0xF01669EF // Used to reset into bootloader -) - -// USB CDC pins -const ( - USBCDC_HOSTEN_PIN = D77 // (PA27) host enable - USBCDC_DM_PIN = D78 // (PA24) D- - USBCDC_DP_PIN = D79 // (PA25) D+ -) - -// USB CDC identifiers -const ( - usb_STRING_PRODUCT = "Adafruit Grand Central M4" - usb_STRING_MANUFACTURER = "Adafruit" -) - -var ( - usb_VID uint16 = 0x239A - usb_PID uint16 = 0x8031 -) diff --git a/emb/machine/board_hifive1b.go b/emb/machine/board_hifive1b.go deleted file mode 100644 index a38b6c0..0000000 --- a/emb/machine/board_hifive1b.go +++ /dev/null @@ -1,61 +0,0 @@ -//go:build hifive1b - -package machine - -const ( - D0 = P16 - D1 = P17 - D2 = P18 - D3 = P19 // Green LED/PWM (PWM1_PWM1) - D4 = P20 // PWM (PWM1_PWM0) - D5 = P21 // Blue LED/PWM (PWM1_PWM2) - D6 = P22 // Red LED/PWM (PWM1_PWM3) - D7 = P16 - D8 = NoPin // PWM? - D9 = P01 - D10 = P02 // SPI1_CS0 - D11 = P03 // SPI1_DQ0 - D12 = P04 // SPI1_DQ1 - D13 = P05 // SPI1_SCK - D14 = NoPin // not connected - D15 = P09 // does not seem to work? - D16 = P10 // PWM (PWM2_PWM0) - D17 = P11 // PWM (PWM2_PWM1) - D18 = P12 // SDA (I2C0_SDA)/PWM (PWM2_PWM2) - D19 = P13 // SDL (I2C0_SCL)/PWM (PWM2_PWM3) -) - -const ( - LED = LED1 - LED1 = LED_RED - LED2 = LED_GREEN - LED3 = LED_BLUE - LED_RED = P22 - LED_GREEN = P19 - LED_BLUE = P21 -) - -var DefaultUART = UART0 - -const ( - // TODO: figure out the pin numbers for these. - UART_TX_PIN = D1 - UART_RX_PIN = D0 -) - -// SPI pins -const ( - SPI0_SCK_PIN = NoPin - SPI0_SDO_PIN = NoPin - SPI0_SDI_PIN = NoPin - - SPI1_SCK_PIN = D13 - SPI1_SDO_PIN = D11 - SPI1_SDI_PIN = D12 -) - -// I2C pins -const ( - I2C0_SDA_PIN = D18 - I2C0_SCL_PIN = D19 -) diff --git a/emb/machine/board_hifive1b_baremetal.go b/emb/machine/board_hifive1b_baremetal.go deleted file mode 100644 index f621d3b..0000000 --- a/emb/machine/board_hifive1b_baremetal.go +++ /dev/null @@ -1,12 +0,0 @@ -//go:build fe310 && hifive1b - -package machine - -import "device/sifive" - -// SPI on the HiFive1. -var ( - SPI1 = &SPI{ - Bus: sifive.QSPI1, - } -) diff --git a/emb/machine/board_hw-651.go b/emb/machine/board_hw-651.go deleted file mode 100644 index 5473150..0000000 --- a/emb/machine/board_hw-651.go +++ /dev/null @@ -1,77 +0,0 @@ -//go:build hw_651 - -package machine - -// No-name brand board based on the nRF51822 chip with low frequency crystal on board. -// Pinout (reverse engineered from the board) can be found here: -// https://aviatorahmet.blogspot.com/2020/12/pinout-of-nrf51822-board.html -// https://cr0wg4n.medium.com/pinout-nrf51822-board-hw-651-78da2eda8894 - -const HasLowFrequencyCrystal = true - -var DefaultUART = UART0 - -// GPIO pins on header J1 -const ( - J1_01 = P0_21 - J1_03 = P0_23 - J1_04 = P0_22 - J1_05 = P0_25 - J1_06 = P0_24 - J1_09 = P0_29 - J1_10 = P0_28 - J1_11 = P0_30 - J1_13 = P0_00 - J1_15 = P0_02 - J1_17 = P0_04 - J1_16 = P0_01 - J1_18 = P0_03 -) - -// GPIO pins on header J2 -const ( - J2_01 = P0_20 - J2_03 = P0_18 - J2_04 = P0_19 - J2_07 = P0_16 - J2_08 = P0_15 - J2_09 = P0_14 - J2_10 = P0_13 - J2_11 = P0_12 - J2_12 = P0_11 - J2_13 = P0_10 - J2_14 = P0_09 - J2_15 = P0_08 - J2_16 = P0_07 - J2_17 = P0_06 - J2_18 = P0_05 -) - -// UART pins -const ( - UART_TX_PIN = P0_24 // J1_06 on the board - UART_RX_PIN = P0_25 // J1_05 on the board -) - -// ADC pins -const ( - ADC0 = P0_03 // J1_18 on the board - ADC1 = P0_02 // J1_15 on the board - ADC2 = P0_01 // J1_16 on the board - ADC3 = P0_04 // J1_17 on the board - ADC4 = P0_05 // J2_18 on the board - ADC5 = P0_06 // J2_17 on the board -) - -// I2C pins -const ( - SDA_PIN = P0_30 // J1_11 on the board - SCL_PIN = P0_00 // J1_13 on the board -) - -// SPI pins -const ( - SPI0_SCK_PIN = P0_23 // J1_03 on the board - SPI0_SDO_PIN = P0_21 // J1_01 on the board - SPI0_SDI_PIN = P0_22 // J1_04 on the board -) diff --git a/emb/machine/board_itsybitsy-m0.go b/emb/machine/board_itsybitsy-m0.go deleted file mode 100644 index 0cc6cad..0000000 --- a/emb/machine/board_itsybitsy-m0.go +++ /dev/null @@ -1,110 +0,0 @@ -//go:build sam && atsamd21 && itsybitsy_m0 - -package machine - -// used to reset into bootloader -const resetMagicValue = 0xf01669ef - -// GPIO Pins -const ( - D0 = PA11 // UART0 RX - D1 = PA10 // UART0 TX - D2 = PA14 - D3 = PA09 // PWM available - D4 = PA08 // PWM available - D5 = PA15 // PWM available - D6 = PA20 // PWM available - D7 = PA21 // PWM available - D8 = PA06 // PWM available - D9 = PA07 // PWM available - D10 = PA18 // can be used for PWM or UART1 TX - D11 = PA16 // can be used for PWM or UART1 RX - D12 = PA19 // PWM available - D13 = PA17 // PWM available -) - -// Analog pins -const ( - A0 = PA02 // ADC/AIN[0] - A1 = PB08 // ADC/AIN[2] - A2 = PB09 // ADC/AIN[3] - A3 = PA04 // ADC/AIN[4] - A4 = PA05 // ADC/AIN[5] - A5 = PB02 // ADC/AIN[10] -) - -const ( - LED = D13 -) - -// USBCDC pins -const ( - USBCDC_DM_PIN = PA24 - USBCDC_DP_PIN = PA25 -) - -// UART1 pins -const ( - UART_TX_PIN = D10 - UART_RX_PIN = D11 -) - -// UART1 on the ItsyBitsy M0. -var ( - UART1 = &sercomUSART1 -) - -// I2C pins -const ( - SDA_PIN = PA22 // SDA: SERCOM3/PAD[0] - SCL_PIN = PA23 // SCL: SERCOM3/PAD[1] -) - -// I2C on the ItsyBitsy M0. -var ( - I2C0 = sercomI2CM3 -) - -// SPI pins -const ( - SPI0_SCK_PIN = PB11 // SCK: SERCOM4/PAD[3] - SPI0_SDO_PIN = PB10 // SDO: SERCOM4/PAD[2] - SPI0_SDI_PIN = PA12 // SDI: SERCOM4/PAD[0] -) - -// SPI on the ItsyBitsy M0. -var SPI0 = sercomSPIM4 - -// "Internal" SPI pins; SPI flash is attached to these on ItsyBitsy M0 -const ( - SPI1_CS_PIN = PA27 - SPI1_SCK_PIN = PB23 - SPI1_SDO_PIN = PB22 - SPI1_SDI_PIN = PB03 -) - -// "Internal" SPI on Sercom 5 -var SPI1 = sercomSPIM5 - -// I2S pins -const ( - I2S_SCK_PIN = PA10 - I2S_SDO_PIN = PA08 - I2S_SDI_PIN = NoPin - I2S_WS_PIN = NoPin // TODO: figure out what this is on ItsyBitsy M0. -) - -// USB CDC identifiers -const ( - usb_STRING_PRODUCT = "Adafruit ItsyBitsy M0 Express" - usb_STRING_MANUFACTURER = "Adafruit" -) - -var ( - usb_VID uint16 = 0x239A - usb_PID uint16 = 0x800F -) - -var ( - DefaultUART = UART1 -) diff --git a/emb/machine/board_itsybitsy-m4.go b/emb/machine/board_itsybitsy-m4.go deleted file mode 100644 index 687538e..0000000 --- a/emb/machine/board_itsybitsy-m4.go +++ /dev/null @@ -1,94 +0,0 @@ -//go:build itsybitsy_m4 - -package machine - -// used to reset into bootloader -const resetMagicValue = 0xf01669ef - -// GPIO Pins -const ( - D0 = PA16 // UART0 RX/PWM available - D1 = PA17 // UART0 TX/PWM available - D2 = PA07 - D3 = PB22 - D4 = PA14 // PWM available - D5 = PA15 // PWM available - D6 = PB02 // dotStar clock - D7 = PA18 // PWM available - D8 = PB03 // dotStar data - D9 = PA19 // PWM available - D10 = PA20 // can be used for PWM or UART1 TX - D11 = PA21 // can be used for PWM or UART1 RX - D12 = PA23 // PWM available - D13 = PA22 // PWM available -) - -// Analog pins -const ( - A0 = PA02 // ADC/AIN[0] - A1 = PA05 // ADC/AIN[2] - A2 = PB08 // ADC/AIN[3] - A3 = PB09 // ADC/AIN[4] - A4 = PA04 // ADC/AIN[5] - A5 = PA06 // ADC/AIN[10] -) - -const ( - LED = D13 -) - -// USBCDC pins -const ( - USBCDC_DM_PIN = PA24 - USBCDC_DP_PIN = PA25 -) - -// UART1 pins -const ( - UART_TX_PIN = D1 - UART_RX_PIN = D0 -) - -const ( - UART2_TX_PIN = A4 - UART2_RX_PIN = D2 -) - -var ( - UART1 = &sercomUSART3 - UART2 = &sercomUSART0 - - DefaultUART = UART1 -) - -// I2C pins -const ( - SDA_PIN = PA12 // SDA: SERCOM2/PAD[0] - SCL_PIN = PA13 // SCL: SERCOM2/PAD[1] -) - -// I2C on the ItsyBitsy M4. -var ( - I2C0 = sercomI2CM2 -) - -// SPI pins -const ( - SPI0_SCK_PIN = PA01 // SCK: SERCOM1/PAD[1] - SPI0_SDO_PIN = PA00 // SDO: SERCOM1/PAD[0] - SPI0_SDI_PIN = PB23 // SDI: SERCOM1/PAD[3] -) - -// SPI on the ItsyBitsy M4. -var SPI0 = sercomSPIM1 - -// USB CDC identifiers -const ( - usb_STRING_PRODUCT = "Adafruit ItsyBitsy M4" - usb_STRING_MANUFACTURER = "Adafruit" -) - -var ( - usb_VID uint16 = 0x239A - usb_PID uint16 = 0x802B -) diff --git a/emb/machine/board_itsybitsy-nrf52840.go b/emb/machine/board_itsybitsy-nrf52840.go deleted file mode 100644 index 0e5818f..0000000 --- a/emb/machine/board_itsybitsy-nrf52840.go +++ /dev/null @@ -1,99 +0,0 @@ -//go:build itsybitsy_nrf52840 - -package machine - -const HasLowFrequencyCrystal = true - -// GPIO Pins -const ( - D0 = P0_25 // UART TX - D1 = P0_24 // UART RX - D2 = P1_02 - D3 = P0_06 // LED1 - D4 = P0_29 // Button - D5 = P0_27 - D6 = P1_09 // DotStar Clock - D7 = P1_08 - D8 = P0_08 // DotStar Data - D9 = P0_07 - D10 = P0_05 - D11 = P0_26 - D12 = P0_11 - D13 = P0_12 - D14 = P0_04 // A0 - D15 = P0_30 // A1 - D16 = P0_28 // A2 - D17 = P0_31 // A3 - D18 = P0_02 // A4 - D19 = P0_03 // A5 - D20 = P0_05 // A6 - D21 = P0_16 // I2C SDA - D22 = P0_14 // I2C SCL - D23 = P0_20 // SPI SDI - D24 = P0_15 // SPI SDO - D25 = P0_13 // SPI SCK - D26 = P0_19 // QSPI SCK - D27 = P0_23 // QSPI CS - D28 = P0_21 // QSPI Data 0 - D29 = P0_22 // QSPI Data 1 - D30 = P1_00 // QSPI Data 2 - D31 = P0_17 // QSPI Data 3 -) - -// Analog Pins -const ( - A0 = D14 - A1 = D15 - A2 = D16 - A3 = D17 - A4 = D18 - A5 = D19 - A6 = D20 -) - -const ( - LED = D3 - LED1 = LED - BUTTON = D4 - - QSPI_SCK = D26 - QSPI_CS = D27 - QSPI_DATA0 = D28 - QSPI_DATA1 = D29 - QSPI_DATA2 = D30 - QSPI_DATA3 = D31 -) - -// UART0 pins (logical UART1) -const ( - UART_RX_PIN = D0 - UART_TX_PIN = D1 -) - -// I2C pins -const ( - SDA_PIN = D21 // I2C0 external - SCL_PIN = D22 // I2C0 external -) - -// SPI pins -const ( - SPI0_SCK_PIN = D25 - SPI0_SDO_PIN = D24 - SPI0_SDI_PIN = D23 -) - -// USB CDC identifiers -const ( - usb_STRING_PRODUCT = "Adafruit ItsyBitsy nRF52840 Express" - usb_STRING_MANUFACTURER = "Adafruit" -) - -var ( - usb_VID uint16 = 0x239A - usb_PID uint16 = 0x8051 -) - -var ( - DefaultUART = UART0 -) diff --git a/emb/machine/board_k210.go b/emb/machine/board_k210.go deleted file mode 100644 index 862be25..0000000 --- a/emb/machine/board_k210.go +++ /dev/null @@ -1,354 +0,0 @@ -//go:build maixbit - -// Chip datasheet: https://s3.cn-north-1.amazonaws.com.cn/dl.kendryte.com/documents/kendryte_datasheet_20181011163248_en.pdf - -package machine - -// K210 IO pins. -const ( - P00 Pin = 0 - P01 Pin = 1 - P02 Pin = 2 - P03 Pin = 3 - P04 Pin = 4 - P05 Pin = 5 - P06 Pin = 6 - P07 Pin = 7 - P08 Pin = 8 - P09 Pin = 9 - P10 Pin = 10 - P11 Pin = 11 - P12 Pin = 12 - P13 Pin = 13 - P14 Pin = 14 - P15 Pin = 15 - P16 Pin = 16 - P17 Pin = 17 - P18 Pin = 18 - P19 Pin = 19 - P20 Pin = 20 - P21 Pin = 21 - P22 Pin = 22 - P23 Pin = 23 - P24 Pin = 24 - P25 Pin = 25 - P26 Pin = 26 - P27 Pin = 27 - P28 Pin = 28 - P29 Pin = 29 - P30 Pin = 30 - P31 Pin = 31 - P32 Pin = 32 - P33 Pin = 33 - P34 Pin = 34 - P35 Pin = 35 - P36 Pin = 36 - P37 Pin = 37 - P38 Pin = 38 - P39 Pin = 39 - P40 Pin = 40 - P41 Pin = 41 - P42 Pin = 42 - P43 Pin = 43 - P44 Pin = 44 - P45 Pin = 45 - P46 Pin = 46 - P47 Pin = 47 -) - -type FPIOAFunction uint8 - -// Every pin on the Kendryte K210 is assigned to an FPIOA function. -// Each pin can be configured with every function below. -const ( - FUNC_JTAG_TCLK FPIOAFunction = 0 // JTAG Test Clock - FUNC_JTAG_TDI FPIOAFunction = 1 // JTAG Test Data In - FUNC_JTAG_TMS FPIOAFunction = 2 // JTAG Test Mode Select - FUNC_JTAG_TDO FPIOAFunction = 3 // JTAG Test Data Out - FUNC_SPI0_D0 FPIOAFunction = 4 // SPI0 Data 0 - FUNC_SPI0_D1 FPIOAFunction = 5 // SPI0 Data 1 - FUNC_SPI0_D2 FPIOAFunction = 6 // SPI0 Data 2 - FUNC_SPI0_D3 FPIOAFunction = 7 // SPI0 Data 3 - FUNC_SPI0_D4 FPIOAFunction = 8 // SPI0 Data 4 - FUNC_SPI0_D5 FPIOAFunction = 9 // SPI0 Data 5 - FUNC_SPI0_D6 FPIOAFunction = 10 // SPI0 Data 6 - FUNC_SPI0_D7 FPIOAFunction = 11 // SPI0 Data 7 - FUNC_SPI0_SS0 FPIOAFunction = 12 // SPI0 Chip Select 0 - FUNC_SPI0_SS1 FPIOAFunction = 13 // SPI0 Chip Select 1 - FUNC_SPI0_SS2 FPIOAFunction = 14 // SPI0 Chip Select 2 - FUNC_SPI0_SS3 FPIOAFunction = 15 // SPI0 Chip Select 3 - FUNC_SPI0_ARB FPIOAFunction = 16 // SPI0 Arbitration - FUNC_SPI0_SCLK FPIOAFunction = 17 // SPI0 Serial Clock - FUNC_UARTHS_RX FPIOAFunction = 18 // UART High speed Receiver - FUNC_UARTHS_TX FPIOAFunction = 19 // UART High speed Transmitter - FUNC_RESV6 FPIOAFunction = 20 // Reserved function - FUNC_RESV7 FPIOAFunction = 21 // Reserved function - FUNC_CLK_SPI1 FPIOAFunction = 22 // Clock SPI1 - FUNC_CLK_I2C1 FPIOAFunction = 23 // Clock I2C1 - FUNC_GPIOHS0 FPIOAFunction = 24 // GPIO High speed 0 - FUNC_GPIOHS1 FPIOAFunction = 25 // GPIO High speed 1 - FUNC_GPIOHS2 FPIOAFunction = 26 // GPIO High speed 2 - FUNC_GPIOHS3 FPIOAFunction = 27 // GPIO High speed 3 - FUNC_GPIOHS4 FPIOAFunction = 28 // GPIO High speed 4 - FUNC_GPIOHS5 FPIOAFunction = 29 // GPIO High speed 5 - FUNC_GPIOHS6 FPIOAFunction = 30 // GPIO High speed 6 - FUNC_GPIOHS7 FPIOAFunction = 31 // GPIO High speed 7 - FUNC_GPIOHS8 FPIOAFunction = 32 // GPIO High speed 8 - FUNC_GPIOHS9 FPIOAFunction = 33 // GPIO High speed 9 - FUNC_GPIOHS10 FPIOAFunction = 34 // GPIO High speed 10 - FUNC_GPIOHS11 FPIOAFunction = 35 // GPIO High speed 11 - FUNC_GPIOHS12 FPIOAFunction = 36 // GPIO High speed 12 - FUNC_GPIOHS13 FPIOAFunction = 37 // GPIO High speed 13 - FUNC_GPIOHS14 FPIOAFunction = 38 // GPIO High speed 14 - FUNC_GPIOHS15 FPIOAFunction = 39 // GPIO High speed 15 - FUNC_GPIOHS16 FPIOAFunction = 40 // GPIO High speed 16 - FUNC_GPIOHS17 FPIOAFunction = 41 // GPIO High speed 17 - FUNC_GPIOHS18 FPIOAFunction = 42 // GPIO High speed 18 - FUNC_GPIOHS19 FPIOAFunction = 43 // GPIO High speed 19 - FUNC_GPIOHS20 FPIOAFunction = 44 // GPIO High speed 20 - FUNC_GPIOHS21 FPIOAFunction = 45 // GPIO High speed 21 - FUNC_GPIOHS22 FPIOAFunction = 46 // GPIO High speed 22 - FUNC_GPIOHS23 FPIOAFunction = 47 // GPIO High speed 23 - FUNC_GPIOHS24 FPIOAFunction = 48 // GPIO High speed 24 - FUNC_GPIOHS25 FPIOAFunction = 49 // GPIO High speed 25 - FUNC_GPIOHS26 FPIOAFunction = 50 // GPIO High speed 26 - FUNC_GPIOHS27 FPIOAFunction = 51 // GPIO High speed 27 - FUNC_GPIOHS28 FPIOAFunction = 52 // GPIO High speed 28 - FUNC_GPIOHS29 FPIOAFunction = 53 // GPIO High speed 29 - FUNC_GPIOHS30 FPIOAFunction = 54 // GPIO High speed 30 - FUNC_GPIOHS31 FPIOAFunction = 55 // GPIO High speed 31 - FUNC_GPIO0 FPIOAFunction = 56 // GPIO pin 0 - FUNC_GPIO1 FPIOAFunction = 57 // GPIO pin 1 - FUNC_GPIO2 FPIOAFunction = 58 // GPIO pin 2 - FUNC_GPIO3 FPIOAFunction = 59 // GPIO pin 3 - FUNC_GPIO4 FPIOAFunction = 60 // GPIO pin 4 - FUNC_GPIO5 FPIOAFunction = 61 // GPIO pin 5 - FUNC_GPIO6 FPIOAFunction = 62 // GPIO pin 6 - FUNC_GPIO7 FPIOAFunction = 63 // GPIO pin 7 - FUNC_UART1_RX FPIOAFunction = 64 // UART1 Receiver - FUNC_UART1_TX FPIOAFunction = 65 // UART1 Transmitter - FUNC_UART2_RX FPIOAFunction = 66 // UART2 Receiver - FUNC_UART2_TX FPIOAFunction = 67 // UART2 Transmitter - FUNC_UART3_RX FPIOAFunction = 68 // UART3 Receiver - FUNC_UART3_TX FPIOAFunction = 69 // UART3 Transmitter - FUNC_SPI1_D0 FPIOAFunction = 70 // SPI1 Data 0 - FUNC_SPI1_D1 FPIOAFunction = 71 // SPI1 Data 1 - FUNC_SPI1_D2 FPIOAFunction = 72 // SPI1 Data 2 - FUNC_SPI1_D3 FPIOAFunction = 73 // SPI1 Data 3 - FUNC_SPI1_D4 FPIOAFunction = 74 // SPI1 Data 4 - FUNC_SPI1_D5 FPIOAFunction = 75 // SPI1 Data 5 - FUNC_SPI1_D6 FPIOAFunction = 76 // SPI1 Data 6 - FUNC_SPI1_D7 FPIOAFunction = 77 // SPI1 Data 7 - FUNC_SPI1_SS0 FPIOAFunction = 78 // SPI1 Chip Select 0 - FUNC_SPI1_SS1 FPIOAFunction = 79 // SPI1 Chip Select 1 - FUNC_SPI1_SS2 FPIOAFunction = 80 // SPI1 Chip Select 2 - FUNC_SPI1_SS3 FPIOAFunction = 81 // SPI1 Chip Select 3 - FUNC_SPI1_ARB FPIOAFunction = 82 // SPI1 Arbitration - FUNC_SPI1_SCLK FPIOAFunction = 83 // SPI1 Serial Clock - FUNC_SPI_PERIPHERAL_D0 FPIOAFunction = 84 // SPI Peripheral Data 0 - FUNC_SPI_PERIPHERAL_SS FPIOAFunction = 85 // SPI Peripheral Select - FUNC_SPI_PERIPHERAL_SCLK FPIOAFunction = 86 // SPI Peripheral Serial Clock - FUNC_I2S0_MCLK FPIOAFunction = 87 // I2S0 Main Clock - FUNC_I2S0_SCLK FPIOAFunction = 88 // I2S0 Serial Clock(BCLK) - FUNC_I2S0_WS FPIOAFunction = 89 // I2S0 Word Select(LRCLK) - FUNC_I2S0_IN_D0 FPIOAFunction = 90 // I2S0 Serial Data Input 0 - FUNC_I2S0_IN_D1 FPIOAFunction = 91 // I2S0 Serial Data Input 1 - FUNC_I2S0_IN_D2 FPIOAFunction = 92 // I2S0 Serial Data Input 2 - FUNC_I2S0_IN_D3 FPIOAFunction = 93 // I2S0 Serial Data Input 3 - FUNC_I2S0_OUT_D0 FPIOAFunction = 94 // I2S0 Serial Data Output 0 - FUNC_I2S0_OUT_D1 FPIOAFunction = 95 // I2S0 Serial Data Output 1 - FUNC_I2S0_OUT_D2 FPIOAFunction = 96 // I2S0 Serial Data Output 2 - FUNC_I2S0_OUT_D3 FPIOAFunction = 97 // I2S0 Serial Data Output 3 - FUNC_I2S1_MCLK FPIOAFunction = 98 // I2S1 Main Clock - FUNC_I2S1_SCLK FPIOAFunction = 99 // I2S1 Serial Clock(BCLK) - FUNC_I2S1_WS FPIOAFunction = 100 // I2S1 Word Select(LRCLK) - FUNC_I2S1_IN_D0 FPIOAFunction = 101 // I2S1 Serial Data Input 0 - FUNC_I2S1_IN_D1 FPIOAFunction = 102 // I2S1 Serial Data Input 1 - FUNC_I2S1_IN_D2 FPIOAFunction = 103 // I2S1 Serial Data Input 2 - FUNC_I2S1_IN_D3 FPIOAFunction = 104 // I2S1 Serial Data Input 3 - FUNC_I2S1_OUT_D0 FPIOAFunction = 105 // I2S1 Serial Data Output 0 - FUNC_I2S1_OUT_D1 FPIOAFunction = 106 // I2S1 Serial Data Output 1 - FUNC_I2S1_OUT_D2 FPIOAFunction = 107 // I2S1 Serial Data Output 2 - FUNC_I2S1_OUT_D3 FPIOAFunction = 108 // I2S1 Serial Data Output 3 - FUNC_I2S2_MCLK FPIOAFunction = 109 // I2S2 Main Clock - FUNC_I2S2_SCLK FPIOAFunction = 110 // I2S2 Serial Clock(BCLK) - FUNC_I2S2_WS FPIOAFunction = 111 // I2S2 Word Select(LRCLK) - FUNC_I2S2_IN_D0 FPIOAFunction = 112 // I2S2 Serial Data Input 0 - FUNC_I2S2_IN_D1 FPIOAFunction = 113 // I2S2 Serial Data Input 1 - FUNC_I2S2_IN_D2 FPIOAFunction = 114 // I2S2 Serial Data Input 2 - FUNC_I2S2_IN_D3 FPIOAFunction = 115 // I2S2 Serial Data Input 3 - FUNC_I2S2_OUT_D0 FPIOAFunction = 116 // I2S2 Serial Data Output 0 - FUNC_I2S2_OUT_D1 FPIOAFunction = 117 // I2S2 Serial Data Output 1 - FUNC_I2S2_OUT_D2 FPIOAFunction = 118 // I2S2 Serial Data Output 2 - FUNC_I2S2_OUT_D3 FPIOAFunction = 119 // I2S2 Serial Data Output 3 - FUNC_RESV0 FPIOAFunction = 120 // Reserved function - FUNC_RESV1 FPIOAFunction = 121 // Reserved function - FUNC_RESV2 FPIOAFunction = 122 // Reserved function - FUNC_RESV3 FPIOAFunction = 123 // Reserved function - FUNC_RESV4 FPIOAFunction = 124 // Reserved function - FUNC_RESV5 FPIOAFunction = 125 // Reserved function - FUNC_I2C0_SCLK FPIOAFunction = 126 // I2C0 Serial Clock - FUNC_I2C0_SDA FPIOAFunction = 127 // I2C0 Serial Data - FUNC_I2C1_SCLK FPIOAFunction = 128 // I2C1 Serial Clock - FUNC_I2C1_SDA FPIOAFunction = 129 // I2C1 Serial Data - FUNC_I2C2_SCLK FPIOAFunction = 130 // I2C2 Serial Clock - FUNC_I2C2_SDA FPIOAFunction = 131 // I2C2 Serial Data - FUNC_CMOS_XCLK FPIOAFunction = 132 // DVP System Clock - FUNC_CMOS_RST FPIOAFunction = 133 // DVP System Reset - FUNC_CMOS_PWDN FPIOAFunction = 134 // DVP Power Down Mode - FUNC_CMOS_VSYNC FPIOAFunction = 135 // DVP Vertical Sync - FUNC_CMOS_HREF FPIOAFunction = 136 // DVP Horizontal Reference output - FUNC_CMOS_PCLK FPIOAFunction = 137 // Pixel Clock - FUNC_CMOS_D0 FPIOAFunction = 138 // Data Bit 0 - FUNC_CMOS_D1 FPIOAFunction = 139 // Data Bit 1 - FUNC_CMOS_D2 FPIOAFunction = 140 // Data Bit 2 - FUNC_CMOS_D3 FPIOAFunction = 141 // Data Bit 3 - FUNC_CMOS_D4 FPIOAFunction = 142 // Data Bit 4 - FUNC_CMOS_D5 FPIOAFunction = 143 // Data Bit 5 - FUNC_CMOS_D6 FPIOAFunction = 144 // Data Bit 6 - FUNC_CMOS_D7 FPIOAFunction = 145 // Data Bit 7 - FUNC_SCCB_SCLK FPIOAFunction = 146 // SCCB Serial Clock - FUNC_SCCB_SDA FPIOAFunction = 147 // SCCB Serial Data - FUNC_UART1_CTS FPIOAFunction = 148 // UART1 Clear To Send - FUNC_UART1_DSR FPIOAFunction = 149 // UART1 Data Set Ready - FUNC_UART1_DCD FPIOAFunction = 150 // UART1 Data Carrier Detect - FUNC_UART1_RI FPIOAFunction = 151 // UART1 Ring Indicator - FUNC_UART1_SIR_IN FPIOAFunction = 152 // UART1 Serial Infrared Input - FUNC_UART1_DTR FPIOAFunction = 153 // UART1 Data Terminal Ready - FUNC_UART1_RTS FPIOAFunction = 154 // UART1 Request To Send - FUNC_UART1_OUT2 FPIOAFunction = 155 // UART1 User-designated Output 2 - FUNC_UART1_OUT1 FPIOAFunction = 156 // UART1 User-designated Output 1 - FUNC_UART1_SIR_OUT FPIOAFunction = 157 // UART1 Serial Infrared Output - FUNC_UART1_BAUD FPIOAFunction = 158 // UART1 Transmit Clock Output - FUNC_UART1_RE FPIOAFunction = 159 // UART1 Receiver Output Enable - FUNC_UART1_DE FPIOAFunction = 160 // UART1 Driver Output Enable - FUNC_UART1_RS485_EN FPIOAFunction = 161 // UART1 RS485 Enable - FUNC_UART2_CTS FPIOAFunction = 162 // UART2 Clear To Send - FUNC_UART2_DSR FPIOAFunction = 163 // UART2 Data Set Ready - FUNC_UART2_DCD FPIOAFunction = 164 // UART2 Data Carrier Detect - FUNC_UART2_RI FPIOAFunction = 165 // UART2 Ring Indicator - FUNC_UART2_SIR_IN FPIOAFunction = 166 // UART2 Serial Infrared Input - FUNC_UART2_DTR FPIOAFunction = 167 // UART2 Data Terminal Ready - FUNC_UART2_RTS FPIOAFunction = 168 // UART2 Request To Send - FUNC_UART2_OUT2 FPIOAFunction = 169 // UART2 User-designated Output 2 - FUNC_UART2_OUT1 FPIOAFunction = 170 // UART2 User-designated Output 1 - FUNC_UART2_SIR_OUT FPIOAFunction = 171 // UART2 Serial Infrared Output - FUNC_UART2_BAUD FPIOAFunction = 172 // UART2 Transmit Clock Output - FUNC_UART2_RE FPIOAFunction = 173 // UART2 Receiver Output Enable - FUNC_UART2_DE FPIOAFunction = 174 // UART2 Driver Output Enable - FUNC_UART2_RS485_EN FPIOAFunction = 175 // UART2 RS485 Enable - FUNC_UART3_CTS FPIOAFunction = 176 // UART3 Clear To Send - FUNC_UART3_DSR FPIOAFunction = 177 // UART3 Data Set Ready - FUNC_UART3_DCD FPIOAFunction = 178 // UART3 Data Carrier Detect - FUNC_UART3_RI FPIOAFunction = 179 // UART3 Ring Indicator - FUNC_UART3_SIR_IN FPIOAFunction = 180 // UART3 Serial Infrared Input - FUNC_UART3_DTR FPIOAFunction = 181 // UART3 Data Terminal Ready - FUNC_UART3_RTS FPIOAFunction = 182 // UART3 Request To Send - FUNC_UART3_OUT2 FPIOAFunction = 183 // UART3 User-designated Output 2 - FUNC_UART3_OUT1 FPIOAFunction = 184 // UART3 User-designated Output 1 - FUNC_UART3_SIR_OUT FPIOAFunction = 185 // UART3 Serial Infrared Output - FUNC_UART3_BAUD FPIOAFunction = 186 // UART3 Transmit Clock Output - FUNC_UART3_RE FPIOAFunction = 187 // UART3 Receiver Output Enable - FUNC_UART3_DE FPIOAFunction = 188 // UART3 Driver Output Enable - FUNC_UART3_RS485_EN FPIOAFunction = 189 // UART3 RS485 Enable - FUNC_TIMER0_TOGGLE1 FPIOAFunction = 190 // TIMER0 Toggle Output 1 - FUNC_TIMER0_TOGGLE2 FPIOAFunction = 191 // TIMER0 Toggle Output 2 - FUNC_TIMER0_TOGGLE3 FPIOAFunction = 192 // TIMER0 Toggle Output 3 - FUNC_TIMER0_TOGGLE4 FPIOAFunction = 193 // TIMER0 Toggle Output 4 - FUNC_TIMER1_TOGGLE1 FPIOAFunction = 194 // TIMER1 Toggle Output 1 - FUNC_TIMER1_TOGGLE2 FPIOAFunction = 195 // TIMER1 Toggle Output 2 - FUNC_TIMER1_TOGGLE3 FPIOAFunction = 196 // TIMER1 Toggle Output 3 - FUNC_TIMER1_TOGGLE4 FPIOAFunction = 197 // TIMER1 Toggle Output 4 - FUNC_TIMER2_TOGGLE1 FPIOAFunction = 198 // TIMER2 Toggle Output 1 - FUNC_TIMER2_TOGGLE2 FPIOAFunction = 199 // TIMER2 Toggle Output 2 - FUNC_TIMER2_TOGGLE3 FPIOAFunction = 200 // TIMER2 Toggle Output 3 - FUNC_TIMER2_TOGGLE4 FPIOAFunction = 201 // TIMER2 Toggle Output 4 - FUNC_CLK_SPI2 FPIOAFunction = 202 // Clock SPI2 - FUNC_CLK_I2C2 FPIOAFunction = 203 // Clock I2C2 - FUNC_INTERNAL0 FPIOAFunction = 204 // Internal function signal 0 - FUNC_INTERNAL1 FPIOAFunction = 205 // Internal function signal 1 - FUNC_INTERNAL2 FPIOAFunction = 206 // Internal function signal 2 - FUNC_INTERNAL3 FPIOAFunction = 207 // Internal function signal 3 - FUNC_INTERNAL4 FPIOAFunction = 208 // Internal function signal 4 - FUNC_INTERNAL5 FPIOAFunction = 209 // Internal function signal 5 - FUNC_INTERNAL6 FPIOAFunction = 210 // Internal function signal 6 - FUNC_INTERNAL7 FPIOAFunction = 211 // Internal function signal 7 - FUNC_INTERNAL8 FPIOAFunction = 212 // Internal function signal 8 - FUNC_INTERNAL9 FPIOAFunction = 213 // Internal function signal 9 - FUNC_INTERNAL10 FPIOAFunction = 214 // Internal function signal 10 - FUNC_INTERNAL11 FPIOAFunction = 215 // Internal function signal 11 - FUNC_INTERNAL12 FPIOAFunction = 216 // Internal function signal 12 - FUNC_INTERNAL13 FPIOAFunction = 217 // Internal function signal 13 - FUNC_INTERNAL14 FPIOAFunction = 218 // Internal function signal 14 - FUNC_INTERNAL15 FPIOAFunction = 219 // Internal function signal 15 - FUNC_INTERNAL16 FPIOAFunction = 220 // Internal function signal 16 - FUNC_INTERNAL17 FPIOAFunction = 221 // Internal function signal 17 - FUNC_CONSTANT FPIOAFunction = 222 // Constant function - FUNC_INTERNAL18 FPIOAFunction = 223 // Internal function signal 18 - FUNC_DEBUG0 FPIOAFunction = 224 // Debug function 0 - FUNC_DEBUG1 FPIOAFunction = 225 // Debug function 1 - FUNC_DEBUG2 FPIOAFunction = 226 // Debug function 2 - FUNC_DEBUG3 FPIOAFunction = 227 // Debug function 3 - FUNC_DEBUG4 FPIOAFunction = 228 // Debug function 4 - FUNC_DEBUG5 FPIOAFunction = 229 // Debug function 5 - FUNC_DEBUG6 FPIOAFunction = 230 // Debug function 6 - FUNC_DEBUG7 FPIOAFunction = 231 // Debug function 7 - FUNC_DEBUG8 FPIOAFunction = 232 // Debug function 8 - FUNC_DEBUG9 FPIOAFunction = 233 // Debug function 9 - FUNC_DEBUG10 FPIOAFunction = 234 // Debug function 10 - FUNC_DEBUG11 FPIOAFunction = 235 // Debug function 11 - FUNC_DEBUG12 FPIOAFunction = 236 // Debug function 12 - FUNC_DEBUG13 FPIOAFunction = 237 // Debug function 13 - FUNC_DEBUG14 FPIOAFunction = 238 // Debug function 14 - FUNC_DEBUG15 FPIOAFunction = 239 // Debug function 15 - FUNC_DEBUG16 FPIOAFunction = 240 // Debug function 16 - FUNC_DEBUG17 FPIOAFunction = 241 // Debug function 17 - FUNC_DEBUG18 FPIOAFunction = 242 // Debug function 18 - FUNC_DEBUG19 FPIOAFunction = 243 // Debug function 19 - FUNC_DEBUG20 FPIOAFunction = 244 // Debug function 20 - FUNC_DEBUG21 FPIOAFunction = 245 // Debug function 21 - FUNC_DEBUG22 FPIOAFunction = 246 // Debug function 22 - FUNC_DEBUG23 FPIOAFunction = 247 // Debug function 23 - FUNC_DEBUG24 FPIOAFunction = 248 // Debug function 24 - FUNC_DEBUG25 FPIOAFunction = 249 // Debug function 25 - FUNC_DEBUG26 FPIOAFunction = 250 // Debug function 26 - FUNC_DEBUG27 FPIOAFunction = 251 // Debug function 27 - FUNC_DEBUG28 FPIOAFunction = 252 // Debug function 28 - FUNC_DEBUG29 FPIOAFunction = 253 // Debug function 29 - FUNC_DEBUG30 FPIOAFunction = 254 // Debug function 30 - FUNC_DEBUG31 FPIOAFunction = 255 // Debug function 31 -) - -// These are the default FPIOA values for each function. -// (source: https://github.com/kendryte/kendryte-standalone-sdk/blob/develop/lib/drivers/fpioa.c#L69) -var fpioaFuncDefaults [256]uint32 = [256]uint32{ - 0x00900000, 0x00900001, 0x00900002, 0x00001f03, 0x00b03f04, 0x00b03f05, 0x00b03f06, 0x00b03f07, 0x00b03f08, - 0x00b03f09, 0x00b03f0a, 0x00b03f0b, 0x00001f0c, 0x00001f0d, 0x00001f0e, 0x00001f0f, 0x03900010, 0x00001f11, - 0x00900012, 0x00001f13, 0x00900014, 0x00900015, 0x00001f16, 0x00001f17, 0x00901f18, 0x00901f19, 0x00901f1a, - 0x00901f1b, 0x00901f1c, 0x00901f1d, 0x00901f1e, 0x00901f1f, 0x00901f20, 0x00901f21, 0x00901f22, 0x00901f23, - 0x00901f24, 0x00901f25, 0x00901f26, 0x00901f27, 0x00901f28, 0x00901f29, 0x00901f2a, 0x00901f2b, 0x00901f2c, - 0x00901f2d, 0x00901f2e, 0x00901f2f, 0x00901f30, 0x00901f31, 0x00901f32, 0x00901f33, 0x00901f34, 0x00901f35, - 0x00901f36, 0x00901f37, 0x00901f38, 0x00901f39, 0x00901f3a, 0x00901f3b, 0x00901f3c, 0x00901f3d, 0x00901f3e, - 0x00901f3f, 0x00900040, 0x00001f41, 0x00900042, 0x00001f43, 0x00900044, 0x00001f45, 0x00b03f46, 0x00b03f47, - 0x00b03f48, 0x00b03f49, 0x00b03f4a, 0x00b03f4b, 0x00b03f4c, 0x00b03f4d, 0x00001f4e, 0x00001f4f, 0x00001f50, - 0x00001f51, 0x03900052, 0x00001f53, 0x00b03f54, 0x00900055, 0x00900056, 0x00001f57, 0x00001f58, 0x00001f59, - 0x0090005a, 0x0090005b, 0x0090005c, 0x0090005d, 0x00001f5e, 0x00001f5f, 0x00001f60, 0x00001f61, 0x00001f62, - 0x00001f63, 0x00001f64, 0x00900065, 0x00900066, 0x00900067, 0x00900068, 0x00001f69, 0x00001f6a, 0x00001f6b, - 0x00001f6c, 0x00001f6d, 0x00001f6e, 0x00001f6f, 0x00900070, 0x00900071, 0x00900072, 0x00900073, 0x00001f74, - 0x00001f75, 0x00001f76, 0x00001f77, 0x00000078, 0x00000079, 0x0000007a, 0x0000007b, 0x0000007c, 0x0000007d, - 0x0099107e, 0x0099107f, 0x00991080, 0x00991081, 0x00991082, 0x00991083, 0x00001f84, 0x00001f85, 0x00001f86, - 0x00900087, 0x00900088, 0x00900089, 0x0090008a, 0x0090008b, 0x0090008c, 0x0090008d, 0x0090008e, 0x0090008f, - 0x00900090, 0x00900091, 0x00993092, 0x00993093, 0x00900094, 0x00900095, 0x00900096, 0x00900097, 0x00900098, - 0x00001f99, 0x00001f9a, 0x00001f9b, 0x00001f9c, 0x00001f9d, 0x00001f9e, 0x00001f9f, 0x00001fa0, 0x00001fa1, - 0x009000a2, 0x009000a3, 0x009000a4, 0x009000a5, 0x009000a6, 0x00001fa7, 0x00001fa8, 0x00001fa9, 0x00001faa, - 0x00001fab, 0x00001fac, 0x00001fad, 0x00001fae, 0x00001faf, 0x009000b0, 0x009000b1, 0x009000b2, 0x009000b3, - 0x009000b4, 0x00001fb5, 0x00001fb6, 0x00001fb7, 0x00001fb8, 0x00001fb9, 0x00001fba, 0x00001fbb, 0x00001fbc, - 0x00001fbd, 0x00001fbe, 0x00001fbf, 0x00001fc0, 0x00001fc1, 0x00001fc2, 0x00001fc3, 0x00001fc4, 0x00001fc5, - 0x00001fc6, 0x00001fc7, 0x00001fc8, 0x00001fc9, 0x00001fca, 0x00001fcb, 0x00001fcc, 0x00001fcd, 0x00001fce, - 0x00001fcf, 0x00001fd0, 0x00001fd1, 0x00001fd2, 0x00001fd3, 0x00001fd4, 0x009000d5, 0x009000d6, 0x009000d7, - 0x009000d8, 0x009100d9, 0x00991fda, 0x009000db, 0x009000dc, 0x009000dd, 0x000000de, 0x009000df, 0x00001fe0, - 0x00001fe1, 0x00001fe2, 0x00001fe3, 0x00001fe4, 0x00001fe5, 0x00001fe6, 0x00001fe7, 0x00001fe8, 0x00001fe9, - 0x00001fea, 0x00001feb, 0x00001fec, 0x00001fed, 0x00001fee, 0x00001fef, 0x00001ff0, 0x00001ff1, 0x00001ff2, - 0x00001ff3, 0x00001ff4, 0x00001ff5, 0x00001ff6, 0x00001ff7, 0x00001ff8, 0x00001ff9, 0x00001ffa, 0x00001ffb, - 0x00001ffc, 0x00001ffd, 0x00001ffe, 0x00001fff, -} diff --git a/emb/machine/board_kb2040.go b/emb/machine/board_kb2040.go deleted file mode 100644 index 1a6f353..0000000 --- a/emb/machine/board_kb2040.go +++ /dev/null @@ -1,84 +0,0 @@ -//go:build kb2040 - -package machine - -// Onboard crystal oscillator frequency, in MHz. -const xoscFreq = 12 // MHz - -// GPIO Pins -const ( - D0 = GPIO0 - D1 = GPIO1 - D2 = GPIO2 - D3 = GPIO3 - D4 = GPIO4 - D5 = GPIO5 - D6 = GPIO6 - D7 = GPIO7 - D8 = GPIO8 - D9 = GPIO9 - D10 = GPIO10 -) - -// Analog pins -const ( - A0 = GPIO26 - A1 = GPIO27 - A2 = GPIO28 - A3 = GPIO29 -) - -// Note: there is no user-controllable LED on the KB2040 board -// const LED = notConnected - -// I2C Pins. -const ( - I2C0_SDA_PIN = GPIO12 - I2C0_SCL_PIN = GPIO13 - - I2C1_SDA_PIN = GPIO2 - I2C1_SCL_PIN = GPIO3 - - SDA_PIN = I2C0_SDA_PIN - SCL_PIN = I2C0_SCL_PIN -) - -// SPI default pins -const ( - // Default Serial Clock Bus 0 for SPI communications - SPI0_SCK_PIN = GPIO18 - // Default Serial Out Bus 0 for SPI communications - SPI0_SDO_PIN = GPIO19 // Tx - // Default Serial In Bus 0 for SPI communications - SPI0_SDI_PIN = GPIO20 // Rx - - // Default Serial Clock Bus 1 for SPI communications - SPI1_SCK_PIN = GPIO26 - // Default Serial Out Bus 1 for SPI communications - SPI1_SDO_PIN = GPIO27 // Tx - // Default Serial In Bus 1 for SPI communications - SPI1_SDI_PIN = GPIO28 // Rx -) - -// UART pins -const ( - UART0_TX_PIN = GPIO0 - UART0_RX_PIN = GPIO1 - UART1_TX_PIN = GPIO8 - UART1_RX_PIN = GPIO9 - UART_TX_PIN = UART0_TX_PIN - UART_RX_PIN = UART0_RX_PIN -) - -var DefaultUART = UART0 - -// USB identifiers -const ( - usb_STRING_PRODUCT = "KB2040" - usb_STRING_MANUFACTURER = "Adafruit" -) - -var ( - usb_VID uint16 = 0x239A - usb_PID uint16 = 0x8106 -) diff --git a/emb/machine/board_lgt92.go b/emb/machine/board_lgt92.go deleted file mode 100644 index 71b0508..0000000 --- a/emb/machine/board_lgt92.go +++ /dev/null @@ -1,97 +0,0 @@ -//go:build lgt92 - -package machine - -import ( - "device/stm32" - "runtime/interrupt" -) - -const ( - LED1 = PA12 - LED2 = PA8 - LED3 = PA11 - - LED_RED = LED1 - LED_BLUE = LED2 - LED_GREEN = LED3 - - // Default led - LED = LED1 - - BUTTON = PB14 - - // LG GPS module - GPS_STANDBY_PIN = PB3 - GPS_RESET_PIN = PB4 - GPS_POWER_PIN = PB5 - - MEMS_ACCEL_CS = PE3 - MEMS_ACCEL_INT1 = PE0 - MEMS_ACCEL_INT2 = PE1 - - // SPI - SPI1_SCK_PIN = PA5 - SPI1_SDI_PIN = PA6 - SPI1_SDO_PIN = PA7 - SPI0_SCK_PIN = SPI1_SCK_PIN - SPI0_SDI_PIN = SPI1_SDI_PIN - SPI0_SDO_PIN = SPI1_SDO_PIN - - // LORA RFM95 Radio - RFM95_DIO0_PIN = PC13 - - // TinyGo UART is MCU LPUSART1 - UART_RX_PIN = PA13 - UART_TX_PIN = PA14 - - // TinyGo UART1 is MCU USART1 - UART1_RX_PIN = PB6 - UART1_TX_PIN = PB7 - - // MPU9250 Nine-Axis (Gyro + Accelerometer + Compass) - I2C0_SCL_PIN = PA9 - I2C0_SDA_PIN = PA10 -) - -var DefaultUART = UART0 - -var ( - - // Console UART (LPUSART1) - UART0 = &_UART0 - _UART0 = UART{ - Buffer: NewRingBuffer(), - Bus: stm32.LPUART1, - TxAltFuncSelector: 6, - RxAltFuncSelector: 6, - } - - // Gps UART - UART1 = &_UART1 - _UART1 = UART{ - Buffer: NewRingBuffer(), - Bus: stm32.USART1, - TxAltFuncSelector: 0, - RxAltFuncSelector: 0, - } - - // MPU9250 Nine-Axis (Gyro + Accelerometer + Compass) - I2C1 = &I2C{ - Bus: stm32.I2C1, - AltFuncSelector: 6, - } - I2C0 = I2C1 - - // SPI - SPI0 = &SPI{ - Bus: stm32.SPI1, - } - SPI1 = SPI0 -) - -func init() { - // Enable UARTs Interrupts - UART0.Interrupt = interrupt.New(stm32.IRQ_AES_RNG_LPUART1, _UART0.handleInterrupt) - UART1.Interrupt = interrupt.New(stm32.IRQ_USART1, _UART1.handleInterrupt) -} diff --git a/emb/machine/board_lorae5.go b/emb/machine/board_lorae5.go deleted file mode 100644 index 18b5d8e..0000000 --- a/emb/machine/board_lorae5.go +++ /dev/null @@ -1,97 +0,0 @@ -//go:build lorae5 - -package machine - -import ( - "device/stm32" - "runtime/interrupt" -) - -const ( - // We assume a LED is connected on PB5 - LED = PB5 // Default LED - - // Set the POWER_EN3V3 pin to high to turn - // on the 3.3V power for all peripherals - POWER_EN3V3 = PA9 - - // Set the POWER_EN5V pin to high to turn - // on the 5V bus power for all peripherals - POWER_EN5V = PB10 -) - -// SubGhz (SPI3) -const ( - SPI0_NSS_PIN = PA4 - SPI0_SCK_PIN = PA5 - SPI0_SDO_PIN = PA6 - SPI0_SDI_PIN = PA7 -) - -// UARTS -const ( - // MCU USART1 - UART1_TX_PIN = PB6 - UART1_RX_PIN = PB7 - - // MCU USART2 - UART2_TX_PIN = PA2 - UART2_RX_PIN = PA3 - - // DEFAULT USART - UART_TX_PIN = UART1_TX_PIN - UART_RX_PIN = UART1_RX_PIN - - // I2C2 pins - I2C2_SCL_PIN = PB15 - I2C2_SDA_PIN = PA15 - I2C2_ALT_FUNC = 4 - - // I2C0 alias for I2C2 - I2C0_SDA_PIN = I2C2_SDA_PIN - I2C0_SCL_PIN = I2C2_SCL_PIN -) - -var ( - // Console UART - UART0 = &_UART0 - _UART0 = UART{ - Buffer: NewRingBuffer(), - Bus: stm32.USART1, - TxAltFuncSelector: AF7_USART1_2, - RxAltFuncSelector: AF7_USART1_2, - } - DefaultUART = UART0 - - // Since we treat UART1 as zero, let's also call it by the real name - UART1 = UART0 - - // UART2 - UART2 = &_UART2 - _UART2 = UART{ - Buffer: NewRingBuffer(), - Bus: stm32.USART2, - TxAltFuncSelector: AF7_USART1_2, - RxAltFuncSelector: AF7_USART1_2, - } - - // I2C Busses - I2C2 = &I2C{ - Bus: stm32.I2C2, - AltFuncSelector: I2C2_ALT_FUNC, - } - - // Set "default" I2C bus to I2C2 - I2C0 = I2C2 - - // SPI - SPI3 = &SPI{ - Bus: stm32.SPI3, - } -) - -func init() { - // Enable UARTs Interrupts - UART0.Interrupt = interrupt.New(stm32.IRQ_USART1, _UART0.handleInterrupt) - UART2.Interrupt = interrupt.New(stm32.IRQ_USART2, _UART2.handleInterrupt) -} diff --git a/emb/machine/board_m5paper.go b/emb/machine/board_m5paper.go deleted file mode 100644 index 7c20f4d..0000000 --- a/emb/machine/board_m5paper.go +++ /dev/null @@ -1,112 +0,0 @@ -//go:build m5paper - -package machine - -const ( - IO0 = GPIO0 - IO1 = GPIO1 - IO2 = GPIO2 - IO3 = GPIO3 - IO4 = GPIO4 - IO5 = GPIO5 - IO6 = GPIO6 - IO7 = GPIO7 - IO8 = GPIO8 - IO9 = GPIO9 - IO10 = GPIO10 - IO11 = GPIO11 - IO12 = GPIO12 - IO13 = GPIO13 - IO14 = GPIO14 - IO15 = GPIO15 - IO16 = GPIO16 - IO17 = GPIO17 - IO18 = GPIO18 - IO19 = GPIO19 - IO21 = GPIO21 - IO22 = GPIO22 - IO23 = GPIO23 - IO25 = GPIO25 - IO26 = GPIO26 - IO27 = GPIO27 - IO32 = GPIO32 - IO33 = GPIO33 - IO34 = GPIO34 - IO35 = GPIO35 - IO36 = GPIO36 - IO37 = GPIO37 - IO38 = GPIO38 - IO39 = GPIO39 -) - -const ( - POWER_PIN = IO2 - EXT_POWER_PIN = IO5 - EPD_POWER_PIN = IO23 - - // Buttons - BUTTON_RIGHT = IO39 - BUTTON_PUSH = IO38 - BUTTON_LEFT = IO37 - BUTTON = BUTTON_PUSH - - // Touch Screen Interrupt - TOUCH_INT = IO36 -) - -// SPI pins -const ( - SPI0_SCK_PIN = IO14 - SPI0_SDO_PIN = IO12 - SPI0_SDI_PIN = IO13 - - // EPD (IT8951) - EPD_SCK_PIN = SPI0_SCK_PIN - EPD_SDO_PIN = SPI0_SDO_PIN - EPD_SDI_PIN = SPI0_SDI_PIN - EPD_CS_PIN = IO15 - EPD_BUSY_PIN = IO27 - - // SD CARD - SDCARD_SCK_PIN = SPI0_SCK_PIN - SDCARD_SDO_PIN = SPI0_SDO_PIN - SDCARD_SDI_PIN = SPI0_SDI_PIN - SDCARD_CS_PIN = IO4 -) - -// I2C pins -const ( - SDA0_PIN = IO21 - SCL0_PIN = IO22 - - SDA_PIN = SDA0_PIN - SCL_PIN = SCL0_PIN - - I2C_TEMP_ADDR = 0x44 // temperature sensor (SHT30) - I2C_CLOCK_ADDR = 0x51 // real time clock (BM8563) - I2C_TOUCH_ADDR = 0x5D // touch screen controller (GT911) -) - -// ADC pins -const ( - ADC1 Pin = IO35 - ADC2 Pin = IO36 - - BATTERY_ADC_PIN = ADC1 -) - -// DAC pins -const ( - DAC1 Pin = IO25 - DAC2 Pin = IO26 -) - -// UART pins -const ( - // UART0 (CP2104) - UART0_TX_PIN = IO1 - UART0_RX_PIN = IO3 - - UART_TX_PIN = UART0_TX_PIN - UART_RX_PIN = UART0_RX_PIN -) diff --git a/emb/machine/board_m5stack.go b/emb/machine/board_m5stack.go deleted file mode 100644 index 33c890a..0000000 --- a/emb/machine/board_m5stack.go +++ /dev/null @@ -1,124 +0,0 @@ -//go:build m5stack - -package machine - -const ( - // GND | ADC G35 - // GND | ADC G36 - // GND | RST EN - // G23 MOSI | DAC/SPK G25 - // G19 MISO | DAC G26 - // G18 SCK | 3.3V - // G3 RXD1 | TXD1 G1 - // G16 RXD2 | TXD2 G17 - // G21 SDA | DCL G22 - // G2 GPIO | GPIO G5 - // G12 IIS_SK | IIS_WS G13 - // G15 IIS_OUT | IIS_MK G0 - // HPWR | IIS_IN G34 - // HPWR | 5V - // HPWR | BATTERY - - IO0 = GPIO0 - IO1 = GPIO1 - IO2 = GPIO2 - IO3 = GPIO3 - IO4 = GPIO4 - IO5 = GPIO5 - IO6 = GPIO6 - IO7 = GPIO7 - IO8 = GPIO8 - IO9 = GPIO9 - IO10 = GPIO10 - IO11 = GPIO11 - IO12 = GPIO12 - IO13 = GPIO13 - IO14 = GPIO14 - IO15 = GPIO15 - IO16 = GPIO16 - IO17 = GPIO17 - IO18 = GPIO18 - IO19 = GPIO19 - IO21 = GPIO21 - IO22 = GPIO22 - IO23 = GPIO23 - IO25 = GPIO25 - IO26 = GPIO26 - IO27 = GPIO27 - IO32 = GPIO32 - IO33 = GPIO33 - IO34 = GPIO34 - IO35 = GPIO35 - IO36 = GPIO36 - IO37 = GPIO37 - IO38 = GPIO38 - IO39 = GPIO39 -) - -const ( - // Buttons - BUTTON_A = IO39 - BUTTON_B = IO38 - BUTTON_C = IO37 - BUTTON = BUTTON_A - - // Speaker - SPEAKER_PIN = IO25 -) - -// SPI pins -const ( - SPI0_SCK_PIN = IO18 - SPI0_SDO_PIN = IO23 - SPI0_SDI_PIN = IO19 - SPI0_CS0_PIN = IO14 - - // LCD (ILI9342C) - LCD_SCK_PIN = SPI0_SCK_PIN - LCD_SDO_PIN = SPI0_SDO_PIN - LCD_SDI_PIN = SPI0_SDI_PIN // NoPin ? - LCD_SS_PIN = SPI0_CS0_PIN - LCD_DC_PIN = IO27 - LCD_RST_PIN = IO33 - LCD_BL_PIN = IO32 - - // SD CARD - SDCARD_SCK_PIN = SPI0_SCK_PIN - SDCARD_SDO_PIN = SPI0_SDO_PIN - SDCARD_SDI_PIN = SPI0_SDI_PIN - SDCARD_SS_PIN = IO4 -) - -// I2C pins -const ( - SDA0_PIN = IO21 - SCL0_PIN = IO22 - - SDA_PIN = SDA0_PIN - SCL_PIN = SCL0_PIN -) - -// ADC pins -const ( - ADC1 Pin = IO35 - ADC2 Pin = IO36 -) - -// DAC pins -const ( - DAC1 Pin = IO25 - DAC2 Pin = IO26 -) - -// UART pins -const ( - // UART0 (CP2104) - UART0_TX_PIN = IO1 - UART0_RX_PIN = IO3 - - UART1_TX_PIN = IO17 - UART1_RX_PIN = IO16 - - UART_TX_PIN = UART0_TX_PIN - UART_RX_PIN = UART0_RX_PIN -) diff --git a/emb/machine/board_m5stack_core2.go b/emb/machine/board_m5stack_core2.go deleted file mode 100644 index 773a069..0000000 --- a/emb/machine/board_m5stack_core2.go +++ /dev/null @@ -1,115 +0,0 @@ -//go:build m5stack_core2 - -package machine - -const ( - // GND | ADC G35 - // GND | ADC G36 - // GND | RST EN - // G23 MOSI | DAC G25 - // G38 MISO | DAC G26 - // G18 SCK | 3.3V - // G3 RXD0 | TXD0 G1 - // G13 RXD2 | TXD2 G14 - // G21 intSDA | intSC G22 - // G32 PA_SDA | PA_SCL G33 - // G27 GPIO | GPIO G19 - // G2 I2S_DOUT | I2S_LRCKC G0 - // N/C | PDM_DAT G34 - // N/C | 5V - // N/C | BAT - - IO0 = GPIO0 - IO1 = GPIO1 // U0TXD - IO2 = GPIO2 - IO3 = GPIO3 // U0RXD - IO4 = GPIO4 - IO5 = GPIO5 - IO6 = GPIO6 // SD_CLK - IO7 = GPIO7 // SD_DATA0 - IO8 = GPIO8 // SD_DATA1 - IO9 = GPIO9 // SD_DATA2 - IO10 = GPIO10 // SD_DATA3 - IO11 = GPIO11 // SD_CMD - IO12 = GPIO12 - IO13 = GPIO13 // U0RXD - IO14 = GPIO14 // U1TXD - IO15 = GPIO15 - IO16 = GPIO16 - IO17 = GPIO17 - IO18 = GPIO18 // SPI0_SCK - IO19 = GPIO19 - IO21 = GPIO21 // SDA0 - IO22 = GPIO22 // SCL0 - IO23 = GPIO23 // SPI0_SDO - IO25 = GPIO25 - IO26 = GPIO26 - IO27 = GPIO27 - IO32 = GPIO32 // SDA1 - IO33 = GPIO33 // SCL1 - IO34 = GPIO34 - IO35 = GPIO35 // ADC1 - IO36 = GPIO36 // ADC2 - IO38 = GPIO38 // SPI0_SDI - IO39 = GPIO39 -) - -// SPI pins -const ( - SPI0_SCK_PIN = IO18 - SPI0_SDO_PIN = IO23 - SPI0_SDI_PIN = IO38 - SPI0_CS0_PIN = IO5 - - // LCD (ILI9342C) - LCD_SCK_PIN = SPI0_SCK_PIN - LCD_SDO_PIN = SPI0_SDO_PIN - LCD_SDI_PIN = SPI0_SDI_PIN - LCD_SS_PIN = SPI0_CS0_PIN - LCD_DC_PIN = IO15 - - // SD CARD - SDCARD_SCK_PIN = SPI0_SCK_PIN - SDCARD_SDO_PIN = SPI0_SDO_PIN - SDCARD_SDI_PIN = SPI0_SDI_PIN - SDCARD_SS_PIN = IO4 -) - -// I2C pins -const ( - // Internal I2C (AXP192 / FT6336U / BM8563 / MPU6886) - SDA0_PIN = IO21 - SCL0_PIN = IO22 - - // External I2C (PORT A) - SDA1_PIN = IO32 - SCL1_PIN = IO33 - - SDA_PIN = SDA1_PIN - SCL_PIN = SCL1_PIN -) - -// ADC pins -const ( - ADC1 Pin = IO35 - ADC2 Pin = IO36 -) - -// DAC pins -const ( - DAC1 Pin = IO25 - DAC2 Pin = IO26 -) - -// UART pins -const ( - // UART0 (CP2104) - UART0_TX_PIN = IO1 - UART0_RX_PIN = IO3 - - UART1_TX_PIN = IO14 - UART1_RX_PIN = IO13 - - UART_TX_PIN = UART0_TX_PIN - UART_RX_PIN = UART0_RX_PIN -) diff --git a/emb/machine/board_m5stamp_c3.go b/emb/machine/board_m5stamp_c3.go deleted file mode 100644 index a77e544..0000000 --- a/emb/machine/board_m5stamp_c3.go +++ /dev/null @@ -1,51 +0,0 @@ -//go:build m5stamp_c3 - -package machine - -const ( - IO0 = GPIO0 - IO1 = GPIO1 - IO2 = GPIO2 - IO3 = GPIO3 - IO4 = GPIO4 - IO5 = GPIO5 - IO6 = GPIO6 - IO7 = GPIO7 - IO8 = GPIO8 - IO9 = GPIO9 - IO10 = GPIO10 - IO11 = GPIO11 - IO12 = GPIO12 - IO13 = GPIO13 - IO14 = GPIO14 - IO15 = GPIO15 - IO16 = GPIO16 - IO17 = GPIO17 - IO18 = GPIO18 - IO19 = GPIO19 - IO20 = GPIO20 - IO21 = GPIO21 - - XTAL_32K_P = IO0 - XTAL_32K_N = IO1 - MTMS = IO4 - MTDI = IO5 - MTCK = IO6 - MTDO = IO7 - VDD_SPI = IO11 - SPIHD = IO12 - SPISP = IO13 - SPICS0 = IO14 - SPICLK = IO15 - SPID = IO16 - SPIQ = IO17 - U0RXD = IO20 - U0TXD = IO21 - - UART_TX_PIN = U0TXD - UART_RX_PIN = U0RXD -) - -const ( - WS2812 = IO2 -) diff --git a/emb/machine/board_m5stick_c.go b/emb/machine/board_m5stick_c.go deleted file mode 100644 index 2eeb522..0000000 --- a/emb/machine/board_m5stick_c.go +++ /dev/null @@ -1,117 +0,0 @@ -//go:build m5stick_c - -// This file contains the pin mapping for the M5STACK M5Stick-C device. -// doc: https://docs.m5stack.com/en/core/m5stickc - -package machine - -const ( - // HAT | HY2.0-4P - // | - // GND | GND - // 5V OUT | VOUT - // G26 | G32 SDA - // G36 | G33 SCL - // G0 | - // BAT | - // 3V3 | - // 5V IN | - - IO0 = GPIO0 // CLK - IO1 = GPIO1 // U0TXD - IO2 = GPIO2 - IO3 = GPIO3 // U0RXD - IO4 = GPIO4 - IO5 = GPIO5 // TFT_CS LCD_SS SPI0_SS - IO6 = GPIO6 - IO7 = GPIO7 - IO8 = GPIO8 - IO9 = GPIO9 // IR - IO10 = GPIO10 // LED - IO11 = GPIO11 - IO12 = GPIO12 - IO13 = GPIO13 // TFT_CLK LCD_SCK SPI0_SCK - IO14 = GPIO14 - IO15 = GPIO15 // TFT_MOSI LCD_MOSI SPI0_MOSI - IO16 = GPIO16 - IO17 = GPIO17 - IO18 = GPIO18 // TFT_RST LCD_RST - IO19 = GPIO19 - IO21 = GPIO21 // SDA0 - IO22 = GPIO22 // SCL0 - IO23 = GPIO23 // TFT_DC LCD_DC - IO25 = GPIO25 // - DAC1 - IO26 = GPIO26 // HAT DAC2 - IO27 = GPIO27 - IO32 = GPIO32 // SDA1 / PIN 32 / RXD2 - IO33 = GPIO33 // SCL1 / PIN 33 / TXD2 - IO34 = GPIO34 // MIC_DATA - IO35 = GPIO35 // IRQ0 ADC1 - IO36 = GPIO36 // HAT ADC2 LCD_MISO SPI0_MISO - IO37 = GPIO37 // BUTTON_A, BUTTON_HOME, BUTTON - IO38 = GPIO38 - IO39 = GPIO39 // BUTTON_B, BUTTON_RST -) - -const ( - // Buttons - BUTTON_A = IO37 - BUTTON_B = IO39 - BUTTON_HOME = BUTTON_A - BUTTON_RST = BUTTON_B - BUTTON = BUTTON_A - - // LED - IR = IO9 - LED = IO10 -) - -// SPI pins -const ( - SPI0_SCK_PIN = IO13 - SPI0_SDO_PIN = IO15 - SPI0_CS0_PIN = IO5 - - // LCD () - LCD_SCK_PIN = SPI0_SCK_PIN - LCD_SDO_PIN = SPI0_SDO_PIN - LCD_SS_PIN = SPI0_CS0_PIN - LCD_DC_PIN = IO23 - LCD_RST_PIN = IO18 -) - -// I2C pins -const ( - // Internal I2C (AXP192 / BM8563 / MPU6886) - SDA0_PIN = IO21 - SCL0_PIN = IO22 - - // External I2C (GROOVE PORT) - SDA1_PIN = IO32 - SCL1_PIN = IO33 - - SDA_PIN = SDA1_PIN - SCL_PIN = SCL1_PIN -) - -// ADC pins -const ( - ADC1 Pin = IO35 - ADC2 Pin = IO36 -) - -// DAC pins -const ( - DAC1 Pin = IO25 - DAC2 Pin = IO26 -) - -// UART pins -const ( - // UART0 (CP2104) - UART0_TX_PIN = IO1 - UART0_RX_PIN = IO3 - - UART_TX_PIN = UART0_TX_PIN - UART_RX_PIN = UART0_RX_PIN -) diff --git a/emb/machine/board_macropad-rp2040.go b/emb/machine/board_macropad-rp2040.go deleted file mode 100644 index 78bd2b7..0000000 --- a/emb/machine/board_macropad-rp2040.go +++ /dev/null @@ -1,87 +0,0 @@ -//go:build macropad_rp2040 - -package machine - -const ( - NeopixelCount = 12 - - // Onboard crystal oscillator frequency, in MHz. - xoscFreq = 12 // MHz -) - -const ( - SWITCH = GPIO0 - BUTTON = GPIO0 - - KEY1 = GPIO1 - KEY2 = GPIO2 - KEY3 = GPIO3 - KEY4 = GPIO4 - KEY5 = GPIO5 - KEY6 = GPIO6 - KEY7 = GPIO7 - KEY8 = GPIO8 - KEY9 = GPIO9 - KEY10 = GPIO10 - KEY11 = GPIO11 - KEY12 = GPIO12 - - LED = GPIO13 - - SPEAKER_ENABLE = GPIO14 - SPEAKER = GPIO16 - - ROT_A = GPIO18 - ROT_B = GPIO17 - - OLED_CS = GPIO22 - OLED_RST = GPIO23 - OLED_DC = GPIO24 - - NEOPIXEL = GPIO19 - WS2812 = NEOPIXEL -) - -// I2C Default pins on Raspberry Pico. -const ( - I2C0_SDA_PIN = GPIO20 - I2C0_SCL_PIN = GPIO21 - - I2C1_SDA_PIN = NoPin // not pinned out - I2C1_SCL_PIN = NoPin // not pinned out -) - -// SPI default pins -const ( - // Default Serial Clock Bus 1 for SPI communications - SPI1_SCK_PIN = GPIO26 - // Default Serial Out Bus 1 for SPI communications - SPI1_SDO_PIN = GPIO27 // Tx - // Default Serial In Bus 1 for SPI communications - SPI1_SDI_PIN = GPIO28 // Rx - - SPI0_SCK_PIN = NoPin // not pinned out - SPI0_SDO_PIN = NoPin // not pinned out - SPI0_SDI_PIN = NoPin // not pinned out -) - -// UART pins -const ( - UART0_TX_PIN = GPIO0 - UART0_RX_PIN = GPIO1 - UART_TX_PIN = UART0_TX_PIN - UART_RX_PIN = UART0_RX_PIN -) - -var DefaultUART = UART0 - -// USB identifiers -const ( - usb_STRING_PRODUCT = "MacroPad RP2040" - usb_STRING_MANUFACTURER = "Adafruit" -) - -var ( - usb_VID uint16 = 0x239A - usb_PID uint16 = 0x8107 -) diff --git a/emb/machine/board_maixbit.go b/emb/machine/board_maixbit.go deleted file mode 100644 index 359a9b8..0000000 --- a/emb/machine/board_maixbit.go +++ /dev/null @@ -1,74 +0,0 @@ -//go:build maixbit - -package machine - -// Pins on the MAix Bit. -const ( - D0 = P00 // JTAG_TCLK - D1 = P01 // JTAG_TDI - D2 = P02 // JTAG_TMS - D3 = P03 // JTAG_TDO - D4 = P04 // UARTHS_RX - D5 = P05 // UARTHS_TX - D6 = P06 // RESV0 - D7 = P07 // RESV0 - D8 = P08 // GPIO1 - D9 = P09 // GPIO2 - D10 = P10 // GPIO3 - D11 = P11 // GPIO4 - D12 = P12 // GPIO5 - D13 = P13 // GPIO6 - D14 = P14 // GPIO7 - D15 = P15 // GPIO8 - D16 = P16 // GPIOHS0 - D17 = P17 // GPIOHS1 - D18 = P18 // GPIOHS2 - D19 = P19 // GPIOHS3 - D20 = P20 // GPIOHS4 - D21 = P21 // GPIOHS5 - D22 = P22 // GPIOHS6 - D23 = P23 // GPIOHS7 - D24 = P24 // GPIOHS8 - D25 = P25 // GPIOHS9 - D26 = P26 // GPIOHS10 / SPI0_SDI - D27 = P27 // GPIOHS11 / SPI0_SCLK - D28 = P28 // GPIOHS12 / SPI0_SDO - D29 = P29 // GPIOHS13 - D30 = P30 // GPIOHS14 - D31 = P31 // GPIOHS15 - D32 = P32 // GPIOHS16 - D33 = P33 // GPIOHS17 - D34 = P34 // GPIOHS18 - D35 = P35 // GPIOHS19 -) - -const ( - LED = LED1 - LED1 = LED_RED - LED2 = LED_GREEN - LED3 = LED_BLUE - LED_RED = D13 - LED_GREEN = D12 - LED_BLUE = D14 -) - -var DefaultUART = UART0 - -// Default pins for UARTHS. -const ( - UART_TX_PIN = D5 - UART_RX_PIN = D4 -) - -// SPI pins. -const ( - SPI0_SCK_PIN = D27 - SPI0_SDO_PIN = D28 - SPI0_SDI_PIN = D26 -) - -// I2C pins. -const ( - I2C0_SDA_PIN = D34 - I2C0_SCL_PIN = D35 -) diff --git a/emb/machine/board_maixbit_baremetal.go b/emb/machine/board_maixbit_baremetal.go deleted file mode 100644 index f5a7e8d..0000000 --- a/emb/machine/board_maixbit_baremetal.go +++ /dev/null @@ -1,15 +0,0 @@ -//go:build k210 && maixbit - -package machine - -import "device/kendryte" - -// SPI on the MAix Bit. -var ( - SPI0 = &SPI{ - Bus: kendryte.SPI0, - } - SPI1 = &SPI{ - Bus: kendryte.SPI1, - } -) diff --git a/emb/machine/board_makerfabs-esp32c3spi35.go b/emb/machine/board_makerfabs-esp32c3spi35.go deleted file mode 100644 index 6e4e6f4..0000000 --- a/emb/machine/board_makerfabs-esp32c3spi35.go +++ /dev/null @@ -1,103 +0,0 @@ -//go:build makerfabs_esp32c3spi35 - -// This file contains the pin mappings for the Makerfabs ESP32C3SPI35 board. -// -// The Makerfabs ESP32C3SPI35 is an LCD Touchscreen development board powered -// by the Espressif ESP32-C3 SoC featuring an open-source RISC-V architecture. -// -// Specifications: -// SoC: ESP32-C3-MINI-1-N4, 4MB Flash, RISCV-32bit, 160MHz, 400KB SRAM -// Wireless: WiFi & Bluetooth 5.0 (BLE) -// LCD: 3.5inch TFT LCD (480x320) -// LCD Driver: ILI9488 SPI -// Touch Panel: Capacitive -// Touch Panel Driver: FT6236 -// MicroSD Card Slot -// Mabee Interface -// Dual USB Type-C (one for USB-to-UART and one for native USB) -// -// Website: https://www.makerfabs.com/ep32-c3-risc-v-spi-tft-touch.html -// Wiki: https://wiki.makerfabs.com/ESP32_C3_SPI_3.5_TFT_with_Touch.html -// GitHub: https://github.com/Makerfabs/Makerfabs-ESP32-C3-SPI-TFT-with-Touch -// Schematic: https://github.com/Makerfabs/Makerfabs-ESP32-C3-SPI-TFT-with-Touch/raw/main/Hardware/ESP32-C3%20TFT%20Touch%20v1.1(3.5''%20ili9488).PDF -// Datasheet: https://www.espressif.com/sites/default/files/documentation/esp32-c3-mini-1_datasheet_en.pdf - -package machine - -// Digital pins -const ( - // Pin // Function - // ----- // --------------------- - D0 = GPIO0 // Touchscreen CS - D1 = GPIO1 // MicroSD CS - D2 = GPIO2 // I2C SDA - D3 = GPIO3 // I2C SCL - D4 = GPIO4 // SPI CS - D5 = GPIO5 // SPI SCK - D6 = GPIO6 // SPI SDO - D7 = GPIO7 // SPI SDI - D8 = GPIO8 // Touchscreen Backlight - D9 = GPIO9 // Boot Button - D10 = GPIO10 // TFT D/C - D18 = GPIO18 // USB DM - D19 = GPIO19 // USB DP - D20 = GPIO20 // UART RX - D21 = GPIO21 // UART TX -) - -// Button pin -const ( - BUTTON = BUTTON_BOOT - BUTTON_BOOT = D9 -) - -// TFT pins -const ( - TFT_BL_PIN = D8 - TFT_CS_PIN = SPI_CS_PIN - TFT_DC_PIN = D10 - TFT_SCK_PIN = SPI_SCK_PIN - TFT_SDI_PIN = SPI_SDI_PIN - TFT_SDO_PIN = SPI_SDO_PIN -) - -// Touchscreen pins -const ( - TS_CS_PIN = D0 - TS_SDA_PIN = SDA_PIN - TS_SCL_PIN = SCL_PIN -) - -// MicroSD pins -const ( - SD_CS_PIN = D1 - SD_SCK_PIN = SPI_SCK_PIN - SD_SDI_PIN = SPI_SDI_PIN - SD_SDO_PIN = SPI_SDO_PIN -) - -// USBCDC pins -const ( - USBCDC_DM_PIN = D18 - USBCDC_DP_PIN = D19 -) - -// UART pins -const ( - UART_RX_PIN = D20 - UART_TX_PIN = D21 -) - -// I2C pins -const ( - SDA_PIN = D2 - SCL_PIN = D3 -) - -// SPI pins -const ( - SPI_CS_PIN = D4 - SPI_SCK_PIN = D5 - SPI_SDI_PIN = D7 - SPI_SDO_PIN = D6 -) diff --git a/emb/machine/board_matrixportal-m4.go b/emb/machine/board_matrixportal-m4.go deleted file mode 100644 index b99fcb2..0000000 --- a/emb/machine/board_matrixportal-m4.go +++ /dev/null @@ -1,200 +0,0 @@ -//go:build matrixportal_m4 - -package machine - -// used to reset into bootloader -const resetMagicValue = 0xF01669EF - -// Digital pins -const ( - // Pin // Function SERCOM PWM Interrupt - // ---- // ---------------- ------ --- --------- - D0 = PA01 // UART RX 1[1] PWM EXTI1 - D1 = PA00 // UART TX 1[0] PWM EXTI0 - D2 = PB22 // Button "Up" EXTI6 - D3 = PB23 // Button "Down" EXTI7 - D4 = PA23 // NeoPixel EXTI7 - D5 = PB31 // I2C SDA 5[1] EXTI15 - D6 = PB30 // I2C SCL 5[0] EXTI14 - D7 = PB00 // HUB75 R1 EXTI0 - D8 = PB01 // HUB75 G1 EXTI1 - D9 = PB02 // HUB75 B1 EXTI2 - D10 = PB03 // HUB75 R2 EXTI3 - D11 = PB04 // HUB75 G2 EXTI4 - D12 = PB05 // HUB75 B2 EXTI5 - D13 = PA14 // LED PWM EXTI14 - D14 = PB06 // HUB75 CLK EXTI6 - D15 = PB14 // HUB75 LAT EXTI14 - D16 = PB12 // HUB75 OE EXTI12 - D17 = PB07 // HUB75 ADDR A EXTI7 - D18 = PB08 // HUB75 ADDR B EXTI8 - D19 = PB09 // HUB75 ADDR C EXTI9 - D20 = PB15 // HUB75 ADDR D EXTI15 - D21 = PB13 // HUB75 ADDR E EXTI13 - D22 = PA02 // ADC (A0) EXTI2 - D23 = PA05 // ADC (A1) EXTI5 - D24 = PA04 // ADC (A2) PWM EXTI4 - D25 = PA06 // ADC (A3) PWM EXTI6 - D26 = PA07 // ADC (A4) EXTI7 - D27 = PA12 // ESP32 UART RX 4[1] PWM EXTI12 - D28 = PA13 // ESP32 UART TX 4[0] PWM EXTI13 - D29 = PA20 // ESP32 GPIO0 PWM EXTI4 - D30 = PA21 // ESP32 Reset PWM EXTI5 - D31 = PA22 // ESP32 Busy PWM EXTI6 - D32 = PA18 // ESP32 RTS PWM EXTI2 - D33 = PB17 // ESP32 SPI CS PWM EXTI1 - D34 = PA16 // ESP32 SPI SCK 3[1] PWM EXTI0 - D35 = PA17 // ESP32 SPI SDI 3[0] PWM EXTI1 - D36 = PA19 // ESP32 SPI SDO 1[3] PWM EXTI3 - D37 = NoPin // USB Host enable - D38 = PA24 // USB DM - D39 = PA25 // USB DP - D40 = PA03 // DAC/VREFP - D41 = PB10 // Flash QSPI SCK - D42 = PB11 // Flash QSPI CS - D43 = PA08 // Flash QSPI I00 - D44 = PA09 // Flash QSPI IO1 - D45 = PA10 // Flash QSPI IO2 - D46 = PA11 // Flash QSPI IO3 - D47 = PA27 // LIS3DH IRQ EXTI11 - D48 = PA05 // SPI SCK 0[1] EXTI5 - D49 = PA04 // SPI SDO 0[0] PWM EXTI4 - D50 = PA07 // SPI SDI 0[3] EXTI7 -) - -// Analog pins -const ( - A0 = PA02 // ADC Channel 0 - A1 = PA05 // ADC Channel 5 - A2 = PA04 // ADC Channel 4 - A3 = PA06 // ADC Channel 6 - A4 = PA07 // ADC Channel 7 -) - -// LED pins -const ( - LED = D13 - NEOPIXEL = D4 - WS2812 = D4 -) - -// Button pins -const ( - BUTTON_UP = D2 - BUTTON_DOWN = D3 -) - -// UART pins -const ( - UART1_RX_PIN = D0 // SERCOM1[1] - UART1_TX_PIN = D1 // SERCOM1[0] - - UART2_RX_PIN = D27 // SERCOM4[1] (ESP32 RX) - UART2_TX_PIN = D28 // SERCOM4[0] (ESP32 TX) - - UART_RX_PIN = UART1_RX_PIN - UART_TX_PIN = UART1_TX_PIN -) - -// UART on the MatrixPortal M4 -var ( - UART1 = &sercomUSART1 - UART2 = &sercomUSART4 - - DefaultUART = UART1 -) - -// SPI pins -const ( - SPI0_SCK_PIN = D34 // SERCOM3[1] (ESP32 SCK) - SPI0_SDO_PIN = D36 // SERCOM1[3] (ESP32 SDO) - SPI0_SDI_PIN = D35 // SERCOM3[0] (ESP32 SDI) - - SPI1_SCK_PIN = D48 // SERCOM0[1] - SPI1_SDO_PIN = D49 // SERCOM0[0] - SPI1_SDI_PIN = D50 // SERCOM0[3] - - SPI_SCK_PIN = SPI0_SCK_PIN - SPI_SDO_PIN = SPI0_SDO_PIN - SPI_SDI_PIN = SPI0_SDI_PIN -) - -// I2C pins -const ( - I2C0_SDA_PIN = D5 // SERCOM5[1] - I2C0_SCL_PIN = D6 // SERCOM5[0] - - I2C_SDA_PIN = I2C0_SDA_PIN - I2C_SCL_PIN = I2C0_SCL_PIN - - SDA_PIN = I2C_SDA_PIN // awkward naming required by machine_atsamd51.go - SCL_PIN = I2C_SCL_PIN // -) - -// I2C on the MatrixPortal M4 -var ( - I2C0 = sercomI2CM5 -) - -// ESP32 pins -const ( - NINA_ACK = D31 - NINA_GPIO0 = D29 - NINA_RESETN = D30 - - NINA_RX = UART2_RX_PIN - NINA_TX = UART2_TX_PIN - NINA_RTS = D32 - - NINA_CS = D33 - NINA_SDO = SPI0_SDO_PIN - NINA_SDI = SPI0_SDI_PIN - NINA_SCK = SPI0_SCK_PIN -) - -// SPI on the MatrixPortal M4 -var ( - SPI0 = sercomSPIM3 // BUG: SDO on SERCOM1! - NINA_SPI = SPI0 - - SPI1 = sercomSPIM0 -) - -// HUB75 pins -const ( - HUB75_R1 = D7 - HUB75_G1 = D8 - HUB75_B1 = D9 - HUB75_R2 = D10 - HUB75_G2 = D11 - HUB75_B2 = D12 - - HUB75_CLK = D14 - HUB75_LAT = D15 - HUB75_OE = D16 - HUB75_ADDR_A = D17 - HUB75_ADDR_B = D18 - HUB75_ADDR_C = D19 - HUB75_ADDR_D = D20 - HUB75_ADDR_E = D21 -) - -// USB CDC pins (UART0) -const ( - USBCDC_DM_PIN = D38 - USBCDC_DP_PIN = D39 - - UART0_RX_PIN = USBCDC_DM_PIN - UART0_TX_PIN = USBCDC_DP_PIN -) - -// USB CDC identifiers -const ( - usb_STRING_PRODUCT = "Matrix Portal M4" - usb_STRING_MANUFACTURER = "Adafruit Industries" -) - -var ( - usb_VID uint16 = 0x239A - usb_PID uint16 = 0x80C9 -) diff --git a/emb/machine/board_mch2022.go b/emb/machine/board_mch2022.go deleted file mode 100644 index bc6b600..0000000 --- a/emb/machine/board_mch2022.go +++ /dev/null @@ -1,28 +0,0 @@ -//go:build mch2022 - -package machine - -// See: https://badge.team/docs/badges/mch2022/pinout/ - -const ( - UART_TX_PIN Pin = 1 - UART_RX_PIN Pin = 3 - - WS2812 Pin = 5 - - PowerOn Pin = 19 // Set high to enable power to LEDs and SD card - - // I2C pins - SDA_PIN Pin = 22 - SCL_PIN Pin = 21 - - // SPI and related pins (ICE40 and LCD). - LCD_RESET Pin = 25 - LCD_MODE Pin = 26 - LCD_DC Pin = 33 - SPI0_SCK_PIN Pin = 18 - SPI0_SDO_PIN Pin = 23 - SPI0_SDI_PIN Pin = 35 // connected to ICE40 - SPI0_CS_ICE40_PIN Pin = 27 - SPI0_CS_LCD_PIN Pin = 32 -) diff --git a/emb/machine/board_mdbt50qrx.go b/emb/machine/board_mdbt50qrx.go deleted file mode 100644 index b93bee7..0000000 --- a/emb/machine/board_mdbt50qrx.go +++ /dev/null @@ -1,40 +0,0 @@ -//go:build mdbt50qrx - -package machine - -const HasLowFrequencyCrystal = false - -// GPIO Pins -const ( - D0 = P1_13 // LED1 - D1 = P1_11 // LED2 (not populated by default) - D2 = P0_15 // Button -) - -const ( - LED = D0 -) - -// MDBT50Q-RX dongle does not have pins broken out for the peripherals below, -// however the machine_nrf*.go implementations of I2C/SPI/etc expect the pin -// constants to be defined, so we are defining them all as NoPin -const ( - UART_TX_PIN = NoPin - UART_RX_PIN = NoPin - SDA_PIN = NoPin - SCL_PIN = NoPin - SPI0_SCK_PIN = NoPin - SPI0_SDO_PIN = NoPin - SPI0_SDI_PIN = NoPin -) - -// USB CDC identifiers -const ( - usb_STRING_PRODUCT = "Raytac MDBT50Q - RX" - usb_STRING_MANUFACTURER = "Raytac Corporation" -) - -var ( - usb_VID uint16 = 0x239A - usb_PID uint16 = 0x810B -) diff --git a/emb/machine/board_metro-m4-airlift.go b/emb/machine/board_metro-m4-airlift.go deleted file mode 100644 index 0fd4291..0000000 --- a/emb/machine/board_metro-m4-airlift.go +++ /dev/null @@ -1,136 +0,0 @@ -//go:build metro_m4_airlift - -package machine - -// used to reset into bootloader -const resetMagicValue = 0xf01669ef - -// GPIO Pins -const ( - D0 = PA23 // UART0 RX/PWM available - D1 = PA22 // UART0 TX/PWM available - D2 = PB17 // PWM available - D3 = PB16 // PWM available - D4 = PB13 // PWM available - D5 = PB14 // PWM available - D6 = PB15 // PWM available - D7 = PB12 // PWM available - - D8 = PA21 // PWM available - D9 = PA20 // PWM available - D10 = PA18 // can be used for PWM or UART1 TX - D11 = PA19 // can be used for PWM or UART1 RX - D12 = PA17 // PWM available - D13 = PA16 // PWM available - - D40 = PB22 // built-in neopixel -) - -// Analog pins -const ( - A0 = PA02 // ADC/AIN[0] - A1 = PA05 // ADC/AIN[2] - A2 = PB06 // ADC/AIN[3] - A3 = PB00 // ADC/AIN[4] // NOTE: different between "airlift" and non-airlift versions - A4 = PB08 // ADC/AIN[5] - A5 = PB09 // ADC/AIN[10] -) - -const ( - LED = D13 - WS2812 = D40 -) - -// USBCDC pins -const ( - USBCDC_DM_PIN = PA24 - USBCDC_DP_PIN = PA25 -) - -const ( - UART_TX_PIN = D1 - UART_RX_PIN = D0 -) - -const ( - UART2_TX_PIN = PA04 - UART2_RX_PIN = PA07 -) - -var ( - UART1 = &sercomUSART3 - UART2 = &sercomUSART0 - - DefaultUART = UART1 - - UART_NINA = UART2 -) - -// NINA-W102 settings -const ( - NINA_BAUDRATE = 115200 - NINA_RESET_INVERTED = true - NINA_SOFT_FLOWCONTROL = true -) - -const ( - NINA_CS = PA15 - NINA_ACK = PB04 - NINA_GPIO0 = PB01 - NINA_RESETN = PB05 - - // pins used for the ESP32 connection do not allow hardware - // flow control, which is required. have to emulate with software. - NINA_TX = PA04 - NINA_RX = PA07 - NINA_CTS = NINA_ACK - NINA_RTS = NINA_GPIO0 -) - -// I2C pins -const ( - SDA_PIN = PB02 // SDA: SERCOM5/PAD[0] - SCL_PIN = PB03 // SCL: SERCOM5/PAD[1] -) - -// I2C on the Metro M4. -var ( - I2C0 = sercomI2CM5 -) - -// SPI pins -const ( - SPI0_SCK_PIN = PA13 // SCK: SERCOM2/PAD[1] - SPI0_SDO_PIN = PA12 // SDO: SERCOM2/PAD[0] - SPI0_SDI_PIN = PA14 // SDI: SERCOM2/PAD[2] - - NINA_SDO = SPI0_SDO_PIN - NINA_SDI = SPI0_SDI_PIN - NINA_SCK = SPI0_SCK_PIN -) - -const ( - SPI1_SCK_PIN = D12 // SDI: SERCOM1/PAD[1] - SPI1_SDO_PIN = D11 // SDO: SERCOM1/PAD[3] - SPI1_SDI_PIN = D13 // SCK: SERCOM1/PAD[0] -) - -// SPI on the Metro M4. -var ( - SPI0 = sercomSPIM2 - NINA_SPI = SPI0 -) - -// SPI1 on the Metro M4 on pins 11,12,13 -var SPI1 = sercomSPIM1 - -// USB CDC identifiers -const ( - usb_STRING_PRODUCT = "Adafruit Metro M4 Airlift Lite" - usb_STRING_MANUFACTURER = "Adafruit" -) - -var ( - usb_VID uint16 = 0x239A - usb_PID uint16 = 0x8037 -) diff --git a/emb/machine/board_microbit-v2.go b/emb/machine/board_microbit-v2.go deleted file mode 100644 index 26cfb51..0000000 --- a/emb/machine/board_microbit-v2.go +++ /dev/null @@ -1,119 +0,0 @@ -//go:build microbit_v2 - -package machine - -// The micro:bit does not have a 32kHz crystal on board. -const HasLowFrequencyCrystal = false - -// Buttons on the micro:bit v2 (A and B) -const ( - BUTTON Pin = BUTTONA - BUTTONA Pin = P5 - BUTTONB Pin = P11 -) - -var DefaultUART = UART0 - -// UART pins -const ( - UART_TX_PIN Pin = P34 - UART_RX_PIN Pin = P33 -) - -// ADC pins -const ( - ADC0 Pin = P0 - ADC1 Pin = P1 - ADC2 Pin = P2 -) - -// I2C0 (internal) pins -const ( - SDA_PIN Pin = SDA0_PIN - SCL_PIN Pin = SCL0_PIN - SDA0_PIN Pin = P30 - SCL0_PIN Pin = P31 -) - -// I2C1 (external) pins -const ( - SDA1_PIN Pin = P20 - SCL1_PIN Pin = P19 -) - -// SPI pins -const ( - SPI0_SCK_PIN Pin = P13 - SPI0_SDO_PIN Pin = P15 - SPI0_SDI_PIN Pin = P14 -) - -// GPIO/Analog pins -const ( - P0 Pin = 2 - P1 Pin = 3 - P2 Pin = 4 - P3 Pin = 31 - P4 Pin = 28 - P5 Pin = 14 - P6 Pin = 37 - P7 Pin = 11 - P8 Pin = 10 - P9 Pin = 9 - P10 Pin = 30 - P11 Pin = 23 - P12 Pin = 12 - P13 Pin = 17 - P14 Pin = 1 - P15 Pin = 13 - P16 Pin = 34 - P19 Pin = 26 - P20 Pin = 32 - P21 Pin = 21 - P22 Pin = 22 - P23 Pin = 15 - P24 Pin = 24 - P25 Pin = 19 - P26 Pin = 36 - P27 Pin = 0 - P28 Pin = 20 - P29 Pin = 5 - P30 Pin = 16 - P31 Pin = 8 - P32 Pin = 25 - P33 Pin = 40 - P34 Pin = 6 -) - -// LED matrix pins -const ( - LED_COL_1 Pin = P0_28 - LED_COL_2 Pin = P0_11 - LED_COL_3 Pin = P0_31 - LED_COL_4 Pin = P1_05 - LED_COL_5 Pin = P0_30 - LED_ROW_1 Pin = P0_21 - LED_ROW_2 Pin = P0_22 - LED_ROW_3 Pin = P0_15 - LED_ROW_4 Pin = P0_24 - LED_ROW_5 Pin = P0_19 -) - -// Peripherals -const ( - BUZZER = P27 - CAP_TOUCH = P26 - MIC = P29 - MIC_LED = P28 -) - -// USB CDC identifiers -const ( - usb_STRING_PRODUCT = "BBC micro:bit V2" - usb_STRING_MANUFACTURER = "BBC" -) - -var ( - usb_VID uint16 = 0x0d28 - usb_PID uint16 = 0x0204 -) diff --git a/emb/machine/board_microbit.go b/emb/machine/board_microbit.go deleted file mode 100644 index 719bd1d..0000000 --- a/emb/machine/board_microbit.go +++ /dev/null @@ -1,78 +0,0 @@ -//go:build microbit - -package machine - -// The micro:bit does not have a 32kHz crystal on board. -const HasLowFrequencyCrystal = false - -var DefaultUART = UART0 - -// GPIO/Analog pins -const ( - P0 = P0_03 - P1 = P0_02 - P2 = P0_01 - P3 = P0_04 - P4 = P0_05 - P5 = P0_17 - P6 = P0_12 - P7 = P0_11 - P8 = P0_18 - P9 = P0_10 - P10 = P0_06 - P11 = P0_26 - P12 = P0_20 - P13 = P0_23 - P14 = P0_22 - P15 = P0_21 - P16 = P0_16 -) - -// Buttons on the micro:bit (A and B) -const ( - BUTTONA = P0_17 - BUTTONB = P0_26 - BUTTON = BUTTONA -) - -// UART pins -const ( - UART_TX_PIN = P0_24 - UART_RX_PIN = P0_25 -) - -// ADC pins -const ( - ADC0 = P0_03 // P0 on the board - ADC1 = P0_02 // P1 on the board - ADC2 = P0_01 // P2 on the board -) - -// I2C pins -const ( - SDA_PIN = P0_30 // P20 on the board - SCL_PIN = P0_00 // P19 on the board -) - -// SPI pins -const ( - SPI0_SCK_PIN = P0_23 // P13 on the board - SPI0_SDO_PIN = P0_21 // P15 on the board - SPI0_SDI_PIN = P0_22 // P14 on the board -) - -// LED matrix pins -const ( - LED_COL_1 = P0_04 - LED_COL_2 = P0_05 - LED_COL_3 = P0_06 - LED_COL_4 = P0_07 - LED_COL_5 = P0_08 - LED_COL_6 = P0_09 - LED_COL_7 = P0_10 - LED_COL_8 = P0_11 - LED_COL_9 = P0_12 - LED_ROW_1 = P0_13 - LED_ROW_2 = P0_14 - LED_ROW_3 = P0_15 -) diff --git a/emb/machine/board_mksnanov3.go b/emb/machine/board_mksnanov3.go deleted file mode 100644 index 35fef68..0000000 --- a/emb/machine/board_mksnanov3.go +++ /dev/null @@ -1,142 +0,0 @@ -//go:build mksnanov3 - -// The MKS Robin Nano V3.X board. -// Documented at https://github.com/makerbase-mks/MKS-Robin-Nano-V3.X. - -package machine - -import ( - "device/stm32" - "runtime/interrupt" -) - -// LED is also wired to the SD card card detect (CD) pin. -const LED = PD12 - -// UART pins -const ( - UART_TX_PIN = PB10 - UART_RX_PIN = PB11 -) - -// EXP1 and EXP2 expansion ports for connecting -// the MKS TS35 V2.0 expansion board. -const ( - BEEPER = EXP1_1 - - // LCD pins. - LCD_DC = EXP1_8 - LCD_CS = EXP1_7 - LCD_RS = EXP1_4 - LCD_BACKLIGHT = EXP1_3 - - // Touch pins. Note that some pins are shared with the - // LCD SPI1 interface. - TOUCH_CLK = EXP2_2 - TOUCH_CS = EXP1_5 - TOUCH_DIN = EXP2_6 - TOUCH_DOUT = EXP2_1 - TOUCH_IRQ = EXP1_6 - - BUTTON = BUTTON_JOG - BUTTON_JOG = EXP1_2 - BUTTON_JOG_CCW = EXP2_3 - BUTTON_JOG_CW = EXP2_5 - - EXP1_1 = PC5 - EXP1_2 = PE13 - EXP1_3 = PD13 - EXP1_4 = PC6 - EXP1_5 = PE14 - EXP1_6 = PE15 - EXP1_7 = PD11 - EXP1_8 = PD10 - - EXP2_1 = PA6 - EXP2_2 = PA5 - EXP2_3 = PE8 - EXP2_4 = PE10 - EXP2_5 = PE11 - EXP2_6 = PA7 - EXP2_7 = PE12 -) - -var ( - UART3 = &_UART3 - _UART3 = UART{ - Buffer: NewRingBuffer(), - Bus: stm32.USART3, - TxAltFuncSelector: AF7_USART1_2_3, - RxAltFuncSelector: AF7_USART1_2_3, - } - DefaultUART = UART3 -) - -// set up RX IRQ handler. Follow similar pattern for other UARTx instances -func init() { - UART3.Interrupt = interrupt.New(stm32.IRQ_USART3, _UART3.handleInterrupt) -} - -// SPI pins -const ( - SPI1_SCK_PIN = EXP2_2 - SPI1_SDI_PIN = EXP2_1 - SPI1_SDO_PIN = EXP2_6 - SPI0_SCK_PIN = SPI1_SCK_PIN - SPI0_SDI_PIN = SPI1_SDI_PIN - SPI0_SDO_PIN = SPI1_SDO_PIN -) - -// Since the first interface is named SPI1, both SPI0 and SPI1 refer to SPI1. -var ( - SPI0 = &SPI{ - Bus: stm32.SPI1, - AltFuncSelector: AF5_SPI1_SPI2, - } - SPI1 = SPI0 -) - -const ( - I2C0_SCL_PIN = PB6 - I2C0_SDA_PIN = PB7 -) - -var ( - I2C0 = &I2C{ - Bus: stm32.I2C1, - AltFuncSelector: AF4_I2C1_2_3, - } -) - -// Motor control pins. -const ( - X_ENABLE = PE4 - X_STEP = PE3 - X_DIR = PE2 - X_DIAG = PA15 - X_UART = PD5 - - Y_ENABLE = PE1 - Y_STEP = PE0 - Y_DIR = PB9 - Y_DIAG = PD2 - Y_UART = PD7 - - Z_ENABLE = PB8 - Z_STEP = PB5 - Z_DIR = PB4 - Z_DIAG = PC8 - Z_UART = PD4 - - E0_ENABLE = PB3 - E0_STEP = PD6 - E0_DIR = PD3 - E0_DIAG = PC4 - E0_UART = PD9 - - E1_ENABLE = PA3 - E1_STEP = PD15 - E1_DIR = PA1 - E1_DIAG = PE7 - E1_UART = PD8 -) diff --git a/emb/machine/board_nano-33-ble.go b/emb/machine/board_nano-33-ble.go deleted file mode 100644 index 758d543..0000000 --- a/emb/machine/board_nano-33-ble.go +++ /dev/null @@ -1,128 +0,0 @@ -//go:build nano_33_ble - -// This contains the pin mappings for the Arduino Nano 33 BLE [Sense] boards. -// - https://store.arduino.cc/arduino-nano-33-ble -// - https://store.arduino.cc/arduino-nano-33-ble-sense -// -// ---------------------------------------------------------------------------- -// Flashing -// -// Special version of bossac is required. -// This executable can be obtained two ways: -// 1. In Arduino IDE, install support for the board ("Arduino Mbed OS Nano Boards") -// Search for "tools/bossac/1.9.1-arduino2/bossac" in Arduino IDEs directory -// 2. Download https://downloads.arduino.cc/packages/package_index.json -// Search for "bossac-1.9.1-arduino2" in that file -// Download tarball for your OS and unpack it -// -// Once you have the executable, make it accessible in your PATH as "bossac_arduino2". -// -// It is possible to replace original bossac with this new one (this only adds support for nrf chip). -// In that case make "bossac_arduino2" symlink on it, for the board target to be able to find it. -// -// ---------------------------------------------------------------------------- -// Bluetooth -// -// SoftDevice (s140v7) must be flashed first to enable use of bluetooth on this board. -// See https://github.com/tinygo-org/bluetooth -// -// SoftDevice overwrites original bootloader and flashing method described above is not available anymore. -// Instead, please use debug probe and flash your code with "nano-33-ble-s140v7" target. -package machine - -const HasLowFrequencyCrystal = true - -// Digital Pins -const ( - D2 Pin = P1_11 - D3 Pin = P1_12 - D4 Pin = P1_15 - D5 Pin = P1_13 - D6 Pin = P1_14 - D7 Pin = P0_23 - D8 Pin = P0_21 - D9 Pin = P0_27 - D10 Pin = P1_02 - D11 Pin = P1_01 - D12 Pin = P1_08 - D13 Pin = P0_13 -) - -// Analog pins -const ( - A0 Pin = P0_04 - A1 Pin = P0_05 - A2 Pin = P0_30 - A3 Pin = P0_29 - A4 Pin = P0_31 - A5 Pin = P0_02 - A6 Pin = P0_28 - A7 Pin = P0_03 -) - -// Onboard LEDs -const ( - LED = LED_BUILTIN - LED1 = LED_RED - LED2 = LED_GREEN - LED3 = LED_BLUE - LED_BUILTIN = P0_13 - LED_RED = P0_24 - LED_GREEN = P0_16 - LED_BLUE = P0_06 - LED_PWR = P1_09 -) - -// UART0 pins -const ( - UART_RX_PIN = P1_10 - UART_TX_PIN = P1_03 -) - -// I2C pins -const ( - // Defaults to internal - SDA_PIN = SDA1_PIN - SCL_PIN = SCL1_PIN - - // I2C0 (external) pins - SDA0_PIN = P0_31 - SCL0_PIN = P0_02 - - // I2C1 (internal) pins - SDA1_PIN = P0_14 - SCL1_PIN = P0_15 - - I2C_PULLUP = P1_00 // Set high for I2C to work -) - -// SPI pins -const ( - SPI0_SCK_PIN = P0_13 - SPI0_SDO_PIN = P1_01 - SPI0_SDI_PIN = P1_08 -) - -// Peripherals -const ( - APDS_INT = P0_19 // Proximity (APDS9960) interrupt pin - - LSM_PWR = P0_22 // IMU (LSM9DS1) power - LPS_PWR = P0_22 // Pressure (LPS22HB) power - HTS_PWR = P0_22 // Humidity (HTS221) power - - MIC_PWR = P0_17 // Microphone (MP34DT06JTR) power - MIC_CLK = P0_26 - MIC_DIN = P0_25 -) - -// USB CDC identifiers -const ( - usb_STRING_PRODUCT = "Nano 33 BLE" - usb_STRING_MANUFACTURER = "Arduino" -) - -var ( - usb_VID uint16 = 0x2341 - usb_PID uint16 = 0x805a -) diff --git a/emb/machine/board_nano-rp2040.go b/emb/machine/board_nano-rp2040.go deleted file mode 100644 index 8155523..0000000 --- a/emb/machine/board_nano-rp2040.go +++ /dev/null @@ -1,126 +0,0 @@ -//go:build nano_rp2040 - -// This contains the pin mappings for the Arduino Nano RP2040 Connect board. -// -// Sometimes the board is not detected even when the board is connected to your computer. -// To solve this, place a jumper wire between the REC and GND pins, then connect the board to your computer. -// -// For more information, see: https://store.arduino.cc/nano-rp2040-connect -// Also -// - Datasheets: https://docs.arduino.cc/hardware/nano-rp2040-connect -// - Nano RP2040 Connect technical reference: https://docs.arduino.cc/tutorials/nano-rp2040-connect/rp2040-01-technical-reference -package machine - -// Digital Pins -const ( - D2 Pin = GPIO25 - D3 Pin = GPIO15 - D4 Pin = GPIO16 - D5 Pin = GPIO17 - D6 Pin = GPIO18 - D7 Pin = GPIO19 - D8 Pin = GPIO20 - D9 Pin = GPIO21 - D10 Pin = GPIO5 - D11 Pin = GPIO7 - D12 Pin = GPIO4 - D13 Pin = GPIO6 - D14 Pin = GPIO26 - D15 Pin = GPIO27 - D16 Pin = GPIO28 - D17 Pin = GPIO29 - D18 Pin = GPIO12 - D19 Pin = GPIO13 -) - -// Analog pins -const ( - A0 Pin = ADC0 - A1 Pin = ADC1 - A2 Pin = ADC2 - A3 Pin = ADC3 -) - -// Onboard LED -const ( - LED = GPIO6 -) - -// I2C pins -const ( - I2C0_SDA_PIN Pin = GPIO12 - I2C0_SCL_PIN Pin = GPIO13 - - I2C1_SDA_PIN Pin = GPIO18 - I2C1_SCL_PIN Pin = GPIO19 -) - -// SPI pins. SPI1 not available on Nano RP2040 Connect. -const ( - SPI0_SCK_PIN Pin = GPIO6 - SPI0_SDO_PIN Pin = GPIO7 - SPI0_SDI_PIN Pin = GPIO4 - - // GPIO22 does not have SPI functionality so we set it to avoid interfering with NINA. - SPI1_SCK_PIN Pin = GPIO22 - SPI1_SDO_PIN Pin = GPIO22 - SPI1_SDI_PIN Pin = GPIO22 -) - -var ( - NINA_SPI = SPI1 -) - -// NINA-W102 Pins -const ( - NINA_SCK Pin = GPIO14 - NINA_SDO Pin = GPIO11 - NINA_SDI Pin = GPIO8 - - NINA_CS Pin = GPIO9 - NINA_ACK Pin = GPIO10 - NINA_GPIO0 Pin = GPIO2 - NINA_RESETN Pin = GPIO3 - - NINA_TX Pin = GPIO8 - NINA_RX Pin = GPIO9 - NINA_CTS Pin = GPIO10 - NINA_RTS Pin = GPIO11 -) - -// NINA-W102 settings -const ( - NINA_BAUDRATE = 115200 - NINA_RESET_INVERTED = true - NINA_SOFT_FLOWCONTROL = false -) - -// Onboard crystal oscillator frequency, in MHz. -const ( - xoscFreq = 12 // MHz -) - -// USB CDC identifiers -// https://github.com/arduino/ArduinoCore-mbed/blob/master/variants/NANO_RP2040_CONNECT/pins_arduino.h -const ( - usb_STRING_PRODUCT = "Nano RP2040 Connect" - usb_STRING_MANUFACTURER = "Arduino" -) - -var ( - usb_VID uint16 = 0x2341 - usb_PID uint16 = 0x005e -) - -// UART pins -const ( - UART0_TX_PIN = GPIO0 - UART0_RX_PIN = GPIO1 - UART_TX_PIN = UART0_TX_PIN - UART_RX_PIN = UART0_RX_PIN -) - -// UART_NINA on the Arduino Nano RP2040 connects to the NINA HCI. -var UART_NINA = UART1 - -var DefaultUART = UART0 diff --git a/emb/machine/board_nicenano.go b/emb/machine/board_nicenano.go deleted file mode 100644 index 254e780..0000000 --- a/emb/machine/board_nicenano.go +++ /dev/null @@ -1,79 +0,0 @@ -//go:build nicenano - -package machine - -const HasLowFrequencyCrystal = true - -// GPIO Pins -const ( - D006 = P0_06 - D008 = P0_08 - D017 = P0_17 - D020 = P0_20 - D022 = P0_22 - D024 = P0_24 - D100 = P1_00 - D011 = P0_11 - D104 = P1_04 - D106 = P1_06 - - D004 = P0_04 // AIN2; P0.04 (AIN2) is used to read the voltage of the battery via ADC. It can’t be used for any other function. - D013 = P0_13 // VCC 3.3V; P0.13 on VCC shuts off the power to VCC when you set it to high; This saves on battery immensely for LEDs of all kinds that eat power even when off - D115 = P1_15 - D113 = P1_13 - D031 = P0_31 // AIN7 - D029 = P0_29 // AIN5 - D002 = P0_02 // AIN0 - - D111 = P1_11 - D010 = P0_10 // NFC2 - D009 = P0_09 // NFC1 - - D026 = P0_26 - D012 = P0_12 - D101 = P1_01 - D102 = P1_02 - D107 = P1_07 -) - -// Analog Pins -const ( - AIN2 = P0_04 // Battery - AIN7 = P0_31 - AIN5 = P0_29 - AIN0 = P0_02 -) - -const ( - LED = P0_15 -) - -// UART0 pins (logical UART1) -const ( - UART_RX_PIN = P0_06 - UART_TX_PIN = P0_08 -) - -// I2C pins -const ( - SDA_PIN = P0_17 // I2C0 external - SCL_PIN = P0_20 // I2C0 external -) - -// SPI pins -const ( - SPI0_SCK_PIN = P0_22 // SCK - SPI0_SDO_PIN = P0_24 // SDO - SPI0_SDI_PIN = P1_00 // SDI -) - -// USB CDC identifiers -const ( - usb_STRING_PRODUCT = "nice!nano" - usb_STRING_MANUFACTURER = "Nice Keyboards" -) - -var ( - usb_VID uint16 = 0x239A - usb_PID uint16 = 0x0029 -) diff --git a/emb/machine/board_nodemcu.go b/emb/machine/board_nodemcu.go deleted file mode 100644 index 5157c82..0000000 --- a/emb/machine/board_nodemcu.go +++ /dev/null @@ -1,35 +0,0 @@ -//go:build nodemcu - -// Pinout for the NodeMCU dev kit. - -package machine - -// GPIO pins on the NodeMCU board. -const ( - D0 = GPIO16 - D1 = GPIO5 - D2 = GPIO4 - D3 = GPIO0 - D4 = GPIO2 - D5 = GPIO14 - D6 = GPIO12 - D7 = GPIO13 - D8 = GPIO15 -) - -// Onboard blue LED (on the AI-Thinker module). -const LED = D4 - -// SPI pins -const ( - SPI0_SCK_PIN = D5 - SPI0_SDO_PIN = D7 - SPI0_SDI_PIN = D6 - SPI0_CS0_PIN = D8 -) - -// I2C pins -const ( - SDA_PIN = D2 - SCL_PIN = D1 -) diff --git a/emb/machine/board_nrf51.go b/emb/machine/board_nrf51.go deleted file mode 100644 index 74e2581..0000000 --- a/emb/machine/board_nrf51.go +++ /dev/null @@ -1,43 +0,0 @@ -//go:build nrf51 || microbit - -package machine - -func CPUFrequency() uint32 { - return 16000000 -} - -// Hardware pins -const ( - P0_00 Pin = 0 - P0_01 Pin = 1 - P0_02 Pin = 2 - P0_03 Pin = 3 - P0_04 Pin = 4 - P0_05 Pin = 5 - P0_06 Pin = 6 - P0_07 Pin = 7 - P0_08 Pin = 8 - P0_09 Pin = 9 - P0_10 Pin = 10 - P0_11 Pin = 11 - P0_12 Pin = 12 - P0_13 Pin = 13 - P0_14 Pin = 14 - P0_15 Pin = 15 - P0_16 Pin = 16 - P0_17 Pin = 17 - P0_18 Pin = 18 - P0_19 Pin = 19 - P0_20 Pin = 20 - P0_21 Pin = 21 - P0_22 Pin = 22 - P0_23 Pin = 23 - P0_24 Pin = 24 - P0_25 Pin = 25 - P0_26 Pin = 26 - P0_27 Pin = 27 - P0_28 Pin = 28 - P0_29 Pin = 29 - P0_30 Pin = 30 - P0_31 Pin = 31 -) diff --git a/emb/machine/board_nrf52840-mdk-usb-dongle.go b/emb/machine/board_nrf52840-mdk-usb-dongle.go deleted file mode 100644 index c30555c..0000000 --- a/emb/machine/board_nrf52840-mdk-usb-dongle.go +++ /dev/null @@ -1,48 +0,0 @@ -//go:build nrf52840_mdk_usb_dongle - -package machine - -const HasLowFrequencyCrystal = true - -// LEDs on the nrf52840-mdk-usb-dongle -const ( - LED Pin = LED_GREEN - LED_GREEN Pin = 22 - LED_RED Pin = 23 - LED_BLUE Pin = 24 -) - -// RESET/USR button, depending on value of PSELRESET UICR register -const ( - BUTTON Pin = 18 -) - -// UART pins -const ( - UART_TX_PIN Pin = NoPin - UART_RX_PIN Pin = NoPin -) - -// I2C pins (unused) -const ( - SDA_PIN = NoPin - SCL_PIN = NoPin -) - -// SPI pins (unused) -const ( - SPI0_SCK_PIN = NoPin - SPI0_SDO_PIN = NoPin - SPI0_SDI_PIN = NoPin -) - -// USB CDC identifiers -const ( - usb_STRING_PRODUCT = "Makerdiary nRF52840 MDK USB Dongle" - usb_STRING_MANUFACTURER = "Nordic Semiconductor ASA" -) - -var ( - usb_VID uint16 = 0x1915 - usb_PID uint16 = 0xCAFE -) diff --git a/emb/machine/board_nrf52840-mdk.go b/emb/machine/board_nrf52840-mdk.go deleted file mode 100644 index 20edde9..0000000 --- a/emb/machine/board_nrf52840-mdk.go +++ /dev/null @@ -1,43 +0,0 @@ -//go:build nrf52840_mdk - -package machine - -const HasLowFrequencyCrystal = true - -// LEDs on the nrf52840-mdk (nRF52840 dev board) -const ( - LED_GREEN Pin = 22 - LED_RED Pin = 23 - LED_BLUE Pin = 24 - LED Pin = LED_GREEN -) - -// UART pins -const ( - UART_TX_PIN Pin = 20 - UART_RX_PIN Pin = 19 -) - -// I2C pins (unused) -const ( - SDA_PIN = NoPin - SCL_PIN = NoPin -) - -// SPI pins (unused) -const ( - SPI0_SCK_PIN = NoPin - SPI0_SDO_PIN = NoPin - SPI0_SDI_PIN = NoPin -) - -// USB CDC identifiers -const ( - usb_STRING_PRODUCT = "Makerdiary nRF52840 MDK" - usb_STRING_MANUFACTURER = "Nordic Semiconductor ASA" -) - -var ( - usb_VID uint16 = 0x1915 - usb_PID uint16 = 0xCAFE -) diff --git a/emb/machine/board_nrf52840.go b/emb/machine/board_nrf52840.go deleted file mode 100644 index e7f1f89..0000000 --- a/emb/machine/board_nrf52840.go +++ /dev/null @@ -1,55 +0,0 @@ -//go:build nrf52840 || circuitplay_bluefruit || reelboard || clue || itsybitsy_nrf52840 - -package machine - -// Hardware pins -const ( - P0_00 Pin = 0 - P0_01 Pin = 1 - P0_02 Pin = 2 - P0_03 Pin = 3 - P0_04 Pin = 4 - P0_05 Pin = 5 - P0_06 Pin = 6 - P0_07 Pin = 7 - P0_08 Pin = 8 - P0_09 Pin = 9 - P0_10 Pin = 10 - P0_11 Pin = 11 - P0_12 Pin = 12 - P0_13 Pin = 13 - P0_14 Pin = 14 - P0_15 Pin = 15 - P0_16 Pin = 16 - P0_17 Pin = 17 - P0_18 Pin = 18 - P0_19 Pin = 19 - P0_20 Pin = 20 - P0_21 Pin = 21 - P0_22 Pin = 22 - P0_23 Pin = 23 - P0_24 Pin = 24 - P0_25 Pin = 25 - P0_26 Pin = 26 - P0_27 Pin = 27 - P0_28 Pin = 28 - P0_29 Pin = 29 - P0_30 Pin = 30 - P0_31 Pin = 31 - P1_00 Pin = 32 - P1_01 Pin = 33 - P1_02 Pin = 34 - P1_03 Pin = 35 - P1_04 Pin = 36 - P1_05 Pin = 37 - P1_06 Pin = 38 - P1_07 Pin = 39 - P1_08 Pin = 40 - P1_09 Pin = 41 - P1_10 Pin = 42 - P1_11 Pin = 43 - P1_12 Pin = 44 - P1_13 Pin = 45 - P1_14 Pin = 46 - P1_15 Pin = 47 -) diff --git a/emb/machine/board_nrf52840_generic.go b/emb/machine/board_nrf52840_generic.go deleted file mode 100644 index 1cf30e2..0000000 --- a/emb/machine/board_nrf52840_generic.go +++ /dev/null @@ -1,25 +0,0 @@ -//go:build nrf52840 && nrf52840_generic - -package machine - -var ( - LED = NoPin - SDA_PIN = NoPin - SCL_PIN = NoPin - UART_TX_PIN = NoPin - UART_RX_PIN = NoPin - SPI0_SCK_PIN = NoPin - SPI0_SDO_PIN = NoPin - SPI0_SDI_PIN = NoPin - - // https://pid.codes/org/TinyGo/ - usb_VID uint16 = 0x1209 - usb_PID uint16 = 0x9090 - - usb_STRING_MANUFACTURER = "TinyGo" - usb_STRING_PRODUCT = "nRF52840 Generic board" -) - -var ( - DefaultUART = UART0 -) diff --git a/emb/machine/board_nucleof103rb.go b/emb/machine/board_nucleof103rb.go deleted file mode 100644 index af7a99e..0000000 --- a/emb/machine/board_nucleof103rb.go +++ /dev/null @@ -1,55 +0,0 @@ -//go:build nucleof103rb - -package machine - -import ( - "device/stm32" - "runtime/interrupt" -) - -const ( - LED = LED_BUILTIN - LED_BUILTIN = LED_GREEN - LED_GREEN = PA5 -) - -const ( - BUTTON = BUTTON_USER - BUTTON_USER = PC13 -) - -// UART pins -const ( - UART_TX_PIN = PA2 - UART_RX_PIN = PA3 - UART_ALT_TX_PIN = PD5 - UART_ALT_RX_PIN = PD6 -) - -var ( - // USART2 is the hardware serial port connected to the onboard ST-LINK - // debugger to be exposed as virtual COM port over USB on Nucleo boards. - UART2 = &_UART2 - _UART2 = UART{ - Buffer: NewRingBuffer(), - Bus: stm32.USART2, - } - DefaultUART = UART2 -) - -func init() { - UART2.Interrupt = interrupt.New(stm32.IRQ_USART2, _UART2.handleInterrupt) -} - -// SPI pins -const ( - SPI0_SCK_PIN = PA5 - SPI0_SDI_PIN = PA6 - SPI0_SDO_PIN = PA7 -) - -// I2C pins -const ( - I2C0_SCL_PIN = PB6 - I2C0_SDA_PIN = PB7 -) diff --git a/emb/machine/board_nucleof722ze.go b/emb/machine/board_nucleof722ze.go deleted file mode 100644 index c9a0b01..0000000 --- a/emb/machine/board_nucleof722ze.go +++ /dev/null @@ -1,68 +0,0 @@ -//go:build nucleof722ze - -package machine - -import ( - "device/stm32" - "runtime/interrupt" -) - -const ( - LED = LED_BUILTIN - LED_BUILTIN = LED_GREEN - LED_GREEN = PB0 - LED_BLUE = PB7 - LED_RED = PB14 -) - -const ( - BUTTON = BUTTON_USER - BUTTON_USER = PC13 -) - -// UART pins -const ( - // PD8 and PD9 are connected to the ST-Link Virtual Com Port (VCP) - UART_TX_PIN = PD8 - UART_RX_PIN = PD9 - UART_ALT_FN = 7 // GPIO_AF7_UART3 -) - -var ( - // USART3 is the hardware serial port connected to the onboard ST-LINK - // debugger to be exposed as virtual COM port over USB on Nucleo boards. - UART1 = &_UART1 - _UART1 = UART{ - Buffer: NewRingBuffer(), - Bus: stm32.USART3, - TxAltFuncSelector: UART_ALT_FN, - RxAltFuncSelector: UART_ALT_FN, - } - DefaultUART = UART1 -) - -func init() { - UART1.Interrupt = interrupt.New(stm32.IRQ_USART3, _UART1.handleInterrupt) -} - -// SPI pins -const ( - SPI0_SCK_PIN = PA5 - SPI0_SDI_PIN = PA6 - SPI0_SDO_PIN = PA7 -) - -// I2C pins -const ( - I2C0_SCL_PIN = PB8 - I2C0_SDA_PIN = PB9 -) - -var ( - // I2C1 is documented, alias to I2C0 as well - I2C1 = &I2C{ - Bus: stm32.I2C1, - AltFuncSelector: 4, - } - I2C0 = I2C1 -) diff --git a/emb/machine/board_nucleol031k6.go b/emb/machine/board_nucleol031k6.go deleted file mode 100644 index aea92d8..0000000 --- a/emb/machine/board_nucleol031k6.go +++ /dev/null @@ -1,98 +0,0 @@ -//go:build nucleol031k6 - -package machine - -import ( - "device/stm32" - "runtime/interrupt" -) - -const ( - // Arduino Pins - A0 = PA0 // ADC_IN0 - A1 = PA1 // ADC_IN1 - A2 = PA3 // ADC_IN3 - A3 = PA4 // ADC_IN4 - A4 = PA5 // ADC_IN5 || I2C1_SDA - A5 = PA6 // ADC_IN6 || I2C1_SCL - A6 = PA7 // ADC_IN7 - A7 = PA2 // ADC_IN2 - - D0 = PA10 // USART1_TX - D1 = PA9 // USART1_RX - D2 = PA12 - D3 = PB0 // TIM2_CH3 - D4 = PB7 - D5 = PB6 // TIM16_CH1N - D6 = PB1 // TIM14_CH1 - D9 = PA8 // TIM1_CH1 - D10 = PA11 // SPI_CS || TIM1_CH4 - D11 = PB5 // SPI1_MOSI || TIM3_CH2 - D12 = PB4 // SPI1_MISO - D13 = PB3 // SPI1_SCK -) - -const ( - LED = LED_BUILTIN - LED_BUILTIN = LED_GREEN - LED_GREEN = PB3 -) - -const ( - // This board does not have a user button, so - // use first GPIO pin by default - BUTTON = PA0 -) - -const ( - // UART pins - // PA2 and PA15 are connected to the ST-Link Virtual Com Port (VCP) - UART_TX_PIN = PA2 - UART_RX_PIN = PA15 - - // SPI - SPI1_SCK_PIN = PB3 - SPI1_SDI_PIN = PB5 - SPI1_SDO_PIN = PB4 - SPI0_SCK_PIN = SPI1_SCK_PIN - SPI0_SDI_PIN = SPI1_SDI_PIN - SPI0_SDO_PIN = SPI1_SDO_PIN - - // I2C pins - // PB6 and PB7 are mapped to CN4 pin 7 and CN4 pin 8 respectively with the - // default solder bridge settings - I2C0_SCL_PIN = PB7 - I2C0_SDA_PIN = PB6 - I2C0_ALT_FUNC = 1 -) - -var ( - // USART2 is the hardware serial port connected to the onboard ST-LINK - // debugger to be exposed as virtual COM port over USB on Nucleo boards. - UART1 = &_UART1 - _UART1 = UART{ - Buffer: NewRingBuffer(), - Bus: stm32.USART2, - TxAltFuncSelector: 4, - RxAltFuncSelector: 4, - } - DefaultUART = UART1 - - // I2C1 is documented, alias to I2C0 as well - I2C1 = &I2C{ - Bus: stm32.I2C1, - AltFuncSelector: 1, - } - I2C0 = I2C1 - - // SPI - SPI0 = &SPI{ - Bus: stm32.SPI1, - AltFuncSelector: 0, - } - SPI1 = SPI0 -) - -func init() { - UART1.Interrupt = interrupt.New(stm32.IRQ_USART2, _UART1.handleInterrupt) -} diff --git a/emb/machine/board_nucleol432kc.go b/emb/machine/board_nucleol432kc.go deleted file mode 100644 index 3d09b6c..0000000 --- a/emb/machine/board_nucleol432kc.go +++ /dev/null @@ -1,100 +0,0 @@ -//go:build nucleol432kc - -package machine - -import ( - "device/stm32" - "runtime/interrupt" -) - -const ( - // Arduino Pins - A0 = PA0 - A1 = PA1 - A2 = PA3 - A3 = PA4 - A4 = PA5 - A5 = PA6 - A6 = PA7 - A7 = PA2 - - D0 = PA10 - D1 = PA9 - D2 = PA12 - D3 = PB0 - D4 = PB7 - D5 = PB6 - D6 = PB1 - D7 = PC14 - D8 = PC15 - D9 = PA8 - D10 = PA11 - D11 = PB5 - D12 = PB4 - D13 = PB3 -) - -const ( - LED = LED_BUILTIN - LED_BUILTIN = LED_GREEN - LED_GREEN = PB3 -) - -const ( - // This board does not have a user button, so - // use first GPIO pin by default - BUTTON = PA0 -) - -const ( - // UART pins - // PA2 and PA15 are connected to the ST-Link Virtual Com Port (VCP) - UART_TX_PIN = PA2 - UART_RX_PIN = PA15 - - // I2C pins - // With default solder bridge settings: - // PB6 / Arduino D5 / CN3 Pin 8 is SCL - // PB7 / Arduino D4 / CN3 Pin 7 is SDA - I2C0_SCL_PIN = PB6 - I2C0_SDA_PIN = PB7 - - // SPI pins - SPI1_SCK_PIN = PB3 - SPI1_SDI_PIN = PB5 - SPI1_SDO_PIN = PB4 - SPI0_SCK_PIN = SPI1_SCK_PIN - SPI0_SDI_PIN = SPI1_SDI_PIN - SPI0_SDO_PIN = SPI1_SDO_PIN -) - -var ( - // USART2 is the hardware serial port connected to the onboard ST-LINK - // debugger to be exposed as virtual COM port over USB on Nucleo boards. - UART1 = &_UART1 - _UART1 = UART{ - Buffer: NewRingBuffer(), - Bus: stm32.USART2, - TxAltFuncSelector: 7, - RxAltFuncSelector: 3, - } - DefaultUART = UART1 - - // I2C1 is documented, alias to I2C0 as well - I2C1 = &I2C{ - Bus: stm32.I2C1, - AltFuncSelector: 4, - } - I2C0 = I2C1 - - // SPI1 is documented, alias to SPI0 as well - SPI1 = &SPI{ - Bus: stm32.SPI1, - AltFuncSelector: 5, - } - SPI0 = SPI1 -) - -func init() { - UART1.Interrupt = interrupt.New(stm32.IRQ_USART2, _UART1.handleInterrupt) -} diff --git a/emb/machine/board_nucleol476rg.go b/emb/machine/board_nucleol476rg.go deleted file mode 100644 index 0a173af..0000000 --- a/emb/machine/board_nucleol476rg.go +++ /dev/null @@ -1,105 +0,0 @@ -//go:build nucleol476rg - -// Schematic: https://www.st.com/resource/en/user_manual/um1724-stm32-nucleo64-boards-mb1136-stmicroelectronics.pdf -// Datasheet: https://www.st.com/resource/en/datasheet/stm32l476je.pdf - -package machine - -import ( - "device/stm32" - "runtime/interrupt" -) - -const ( - // Arduino Pins - A0 = PA0 - A1 = PA1 - A2 = PA4 - A3 = PB0 - A4 = PC1 - A5 = PC0 - - D0 = PA3 - D1 = PA2 - D2 = PA10 - D3 = PB3 - D4 = PB5 - D5 = PB4 - D6 = PB10 - D7 = PA8 - D8 = PA9 - D9 = PC7 - D10 = PB6 - D11 = PA7 - D12 = PA6 - D13 = PA5 - D14 = PB9 - D15 = PB8 -) - -// User LD2: the green LED is a user LED connected to ARDUINO® signal D13 corresponding -// to STM32 I/O PA5 (pin 21) or PB13 (pin 34) depending on the STM32 target. -const ( - LED = LED_BUILTIN - LED_BUILTIN = LED_GREEN - LED_GREEN = PA5 -) - -const ( - // This board does not have a user button, so - // use first GPIO pin by default - BUTTON = PA0 -) - -const ( - // UART pins - // PA2 and PA3 are connected to the ST-Link Virtual Com Port (VCP) - UART_TX_PIN = PA2 - UART_RX_PIN = PA3 - - // I2C pins - // With default solder bridge settings: - // PB8 / Arduino D5 / CN3 Pin 8 is SCL - // PB7 / Arduino D4 / CN3 Pin 7 is SDA - I2C0_SCL_PIN = PB8 - I2C0_SDA_PIN = PB9 - - // SPI pins - SPI1_SCK_PIN = PA5 - SPI1_SDI_PIN = PA6 - SPI1_SDO_PIN = PA7 - SPI0_SCK_PIN = SPI1_SCK_PIN - SPI0_SDI_PIN = SPI1_SDI_PIN - SPI0_SDO_PIN = SPI1_SDO_PIN -) - -var ( - // USART2 is the hardware serial port connected to the onboard ST-LINK - // debugger to be exposed as virtual COM port over USB on Nucleo boards. - UART1 = &_UART1 - _UART1 = UART{ - Buffer: NewRingBuffer(), - Bus: stm32.USART2, - TxAltFuncSelector: AF7_USART1_2_3, - RxAltFuncSelector: AF7_USART1_2_3, - } - DefaultUART = UART1 - - // I2C1 is documented, alias to I2C0 as well - I2C1 = &I2C{ - Bus: stm32.I2C1, - AltFuncSelector: AF4_I2C1_2_3, - } - I2C0 = I2C1 - - // SPI1 is documented, alias to SPI0 as well - SPI1 = &SPI{ - Bus: stm32.SPI1, - AltFuncSelector: AF5_SPI1_2, - } - SPI0 = SPI1 -) - -func init() { - UART1.Interrupt = interrupt.New(stm32.IRQ_USART2, _UART1.handleInterrupt) -} diff --git a/emb/machine/board_nucleol552ze.go b/emb/machine/board_nucleol552ze.go deleted file mode 100644 index 6a13d9f..0000000 --- a/emb/machine/board_nucleol552ze.go +++ /dev/null @@ -1,60 +0,0 @@ -//go:build nucleol552ze - -package machine - -import ( - "device/stm32" - "runtime/interrupt" -) - -const ( - LED_GREEN = PC7 - LED_BLUE = PB7 - LED_RED = PA9 - LED_BUILTIN = LED_GREEN - LED = LED_BUILTIN -) - -const ( - BUTTON = BUTTON_USER - BUTTON_USER = PC13 -) - -// UART pins -const ( - // PG7 and PG8 are connected to the ST-Link Virtual Com Port (VCP) - UART_TX_PIN = PG7 - UART_RX_PIN = PG8 - UART_ALT_FN = 8 // GPIO_AF8_LPUART1 -) - -var ( - // LPUART1 is the hardware serial port connected to the onboard ST-LINK - // debugger to be exposed as virtual COM port over USB on Nucleo boards. - UART1 = &_UART1 - _UART1 = UART{ - Buffer: NewRingBuffer(), - Bus: stm32.LPUART1, - TxAltFuncSelector: UART_ALT_FN, - RxAltFuncSelector: UART_ALT_FN, - } - DefaultUART = UART1 -) - -const ( - I2C0_SCL_PIN = PB8 - I2C0_SDA_PIN = PB9 -) - -var ( - // I2C1 is documented, alias to I2C0 as well - I2C1 = &I2C{ - Bus: stm32.I2C1, - AltFuncSelector: 4, - } - I2C0 = I2C1 -) - -func init() { - UART1.Interrupt = interrupt.New(stm32.IRQ_LPUART1, _UART1.handleInterrupt) -} diff --git a/emb/machine/board_nucleowl55jc.go b/emb/machine/board_nucleowl55jc.go deleted file mode 100644 index a8e88dd..0000000 --- a/emb/machine/board_nucleowl55jc.go +++ /dev/null @@ -1,96 +0,0 @@ -//go:build nucleowl55jc - -package machine - -import ( - "device/stm32" - "runtime/interrupt" -) - -const ( - LED_BLUE = PB15 - LED_GREEN = PB9 - LED_RED = PB11 - LED = LED_RED - - BTN1 = PA0 - BTN2 = PA1 - BTN3 = PC6 - BUTTON = BTN1 - - // SubGhz (SPI3) - SPI0_NSS_PIN = PA4 - SPI0_SCK_PIN = PA5 - SPI0_SDO_PIN = PA6 - SPI0_SDI_PIN = PA7 - - //MCU USART1 - UART1_TX_PIN = PB6 - UART1_RX_PIN = PB7 - - //MCU USART2 - UART2_RX_PIN = PA3 - UART2_TX_PIN = PA2 - - // DEFAULT USART - UART_RX_PIN = UART2_RX_PIN - UART_TX_PIN = UART2_TX_PIN - - // I2C1 pins - I2C1_SCL_PIN = PA9 - I2C1_SDA_PIN = PA10 - I2C1_ALT_FUNC = 4 - - // I2C2 pins - I2C2_SCL_PIN = PA12 - I2C2_SDA_PIN = PA11 - I2C2_ALT_FUNC = 4 - - // I2C0 alias for I2C1 - I2C0_SDA_PIN = I2C1_SDA_PIN - I2C0_SCL_PIN = I2C1_SCL_PIN -) - -var ( - // STM32 UART2 is connected to the embedded STLINKV3 Virtual Com Port - UART0 = &_UART0 - _UART0 = UART{ - Buffer: NewRingBuffer(), - Bus: stm32.USART2, - TxAltFuncSelector: 7, - RxAltFuncSelector: 7, - } - - // UART1 is free - UART1 = &_UART1 - _UART1 = UART{ - Buffer: NewRingBuffer(), - Bus: stm32.USART1, - TxAltFuncSelector: 7, - RxAltFuncSelector: 7, - } - - DefaultUART = UART0 - - // I2C Busses - I2C1 = &I2C{ - Bus: stm32.I2C1, - AltFuncSelector: I2C1_ALT_FUNC, - } - I2C2 = &I2C{ - Bus: stm32.I2C2, - AltFuncSelector: I2C2_ALT_FUNC, - } - I2C0 = I2C1 - - // SPI - SPI3 = &SPI{ - Bus: stm32.SPI3, - } -) - -func init() { - // Enable UARTs Interrupts - UART0.Interrupt = interrupt.New(stm32.IRQ_USART2, _UART0.handleInterrupt) - UART1.Interrupt = interrupt.New(stm32.IRQ_USART1, _UART1.handleInterrupt) -} diff --git a/emb/machine/board_p1am-100.go b/emb/machine/board_p1am-100.go deleted file mode 100644 index f2a7d13..0000000 --- a/emb/machine/board_p1am-100.go +++ /dev/null @@ -1,140 +0,0 @@ -//go:build p1am_100 - -// This contains the pin mappings for the ProductivityOpen P1AM-100 board. -// -// For more information, see: https://facts-engineering.github.io/ -package machine - -// used to reset into bootloader -const resetMagicValue = 0x07738135 - -// Note: On the P1AM-100, pins D8, D9, D10, A3, and A4 are used for -// communication with the base controller. - -// GPIO Pins -const ( - D0 Pin = PA22 // PWM available - D1 Pin = PA23 // PWM available - D2 Pin = PA10 // PWM available - D3 Pin = PA11 // PWM available - D4 Pin = PB10 // PWM available - D5 Pin = PB11 // PWM available - D6 Pin = PA20 // PWM available - D7 Pin = PA21 // PWM available - - D8 Pin = PA16 // PWM available - D9 Pin = PA17 - D10 Pin = PA19 // PWM available - D11 Pin = PA08 - D12 Pin = PA09 - D13 Pin = PB23 - D14 Pin = PB22 - - // Remaining pins are shared with analog pins - D15 Pin = PA02 - - D16 Pin = PB02 - D17 Pin = PB03 - D18 Pin = PA04 // PWM available - D19 Pin = PA05 // PWM available - D20 Pin = PA06 - D21 Pin = PA07 -) - -// Analog pins -const ( - A0 Pin = PA02 // ADC/AIN[0] - A1 Pin = PB02 // ADC/AIN[10] - A2 Pin = PB03 // ADC/AIN[11] - A3 Pin = PA04 // ADC/AIN[4] - A4 Pin = PA05 // ADC/AIN[5] - A5 Pin = PA06 // ADC/AIN[6] - A6 Pin = PA07 // ADC/AIN[7] -) - -const ( - SWITCH Pin = PA28 - LED Pin = PB08 - ADC_BATTERY Pin = PB09 // ADC/AIN[3] -) - -// P1AM Base Controller -const ( - BASE_SLAVE_SELECT_PIN Pin = A3 - BASE_SLAVE_ACK_PIN Pin = A4 - BASE_ENABLE_PIN Pin = PB09 -) - -// USBCDC pins -const ( - USBCDC_DM_PIN Pin = PA24 - USBCDC_DP_PIN Pin = PA25 - USBCDC_HOST_ENABLE_PIN Pin = PA18 -) - -// UART1 pins -const ( - UART_RX_PIN Pin = PB23 // RX: SERCOM5/PAD[3] - UART_TX_PIN Pin = PB22 // TX: SERCOM5/PAD[2] -) - -// UART1 on the P1AM-100 connects to the normal TX/RX pins. -var UART1 = &sercomUSART5 - -// I2C pins -const ( - SDA_PIN Pin = PA08 // SDA: SERCOM0/PAD[0] - SCL_PIN Pin = PA09 // SCL: SERCOM0/PAD[1] -) - -// I2C on the P1AM-100. -var ( - I2C0 = sercomI2CM0 -) - -// SPI pins -const ( - SPI0_SCK_PIN Pin = D9 // SCK: SERCOM1/PAD[1] - SPI0_SDO_PIN Pin = D8 // SDO: SERCOM1/PAD[0] - SPI0_SDI_PIN Pin = D10 // SDI: SERCOM1/PAD[3] -) - -// SD card pins -const ( - SDCARD_SDI_PIN Pin = PA15 // SDI: SERCOM2/PAD[3] - SDCARD_SDO_PIN Pin = PA12 // SDO: SERCOM2/PAD[0] - SDCARD_SCK_PIN Pin = PA13 // SCK: SERCOM2/PAD[1] - SDCARD_SS_PIN Pin = PA14 // SS: as GPIO - SDCARD_CD_PIN Pin = PA27 -) - -// SPI on the P1AM-100 is used for Base Controller. -var ( - SPI0 = sercomSPIM1 - BASE_CONTROLLER_SPI = SPI0 -) - -// SPI1 is connected to the SD card slot on the P1AM-100 -var ( - SPI1 = sercomSPIM2 - SDCARD_SPI = SPI1 -) - -// I2S pins -const ( - I2S_SCK_PIN Pin = D2 - I2S_SDO_PIN Pin = A6 - I2S_SDI_PIN = NoPin - I2S_WS_PIN = D3 -) - -// USB CDC identifiers -const ( - usb_STRING_PRODUCT = "P1AM-100" - usb_STRING_MANUFACTURER = "Facts Engineering" -) - -var ( - usb_VID uint16 = 0x1354 - usb_PID uint16 = 0x4000 -) diff --git a/emb/machine/board_particle_argon.go b/emb/machine/board_particle_argon.go deleted file mode 100644 index efd8613..0000000 --- a/emb/machine/board_particle_argon.go +++ /dev/null @@ -1,106 +0,0 @@ -//go:build particle_argon - -package machine - -const HasLowFrequencyCrystal = true - -// More info: https://docs.particle.io/datasheets/wi-fi/argon-datasheet/ -// Board diagram: https://docs.particle.io/assets/images/argon/argon-block-diagram.png - -// GPIOs -const ( - A0 Pin = 3 - A1 Pin = 4 - A2 Pin = 28 - A3 Pin = 29 - A4 Pin = 30 - A5 Pin = 31 - D0 Pin = 26 // Also SDA - D1 Pin = 27 // Also SCL - D2 Pin = 33 - D3 Pin = 34 - D4 Pin = 40 - D5 Pin = 42 - D6 Pin = 43 - D7 Pin = 44 // Also LED - D8 Pin = 35 - D9 Pin = 6 // Also TX - D10 Pin = 8 // Also RX - D11 Pin = 46 // Also SDI - D12 Pin = 45 // Also SDO - D13 Pin = 47 // Also SCK -) - -// LEDs -const ( - LED Pin = 44 - LED_GREEN Pin = 14 - LED_RED Pin = 13 - LED_BLUE Pin = 15 -) - -// UART -var ( - DefaultUART = UART0 -) - -const ( - UART_TX_PIN Pin = 6 - UART_RX_PIN Pin = 8 -) - -// I2C pins -const ( - SDA_PIN Pin = 26 - SCL_PIN Pin = 27 -) - -// SPI pins -const ( - SPI0_SCK_PIN Pin = 47 - SPI0_SDO_PIN Pin = 45 - SPI0_SDI_PIN Pin = 46 -) - -// Internal 4MB SPI Flash -const ( - SPI1_SCK_PIN Pin = 19 - SPI1_SDO_PIN Pin = 20 - SPI1_SDI_PIN Pin = 21 - SPI1_CS_PIN Pin = 17 - SPI1_WP_PIN Pin = 22 - SPI1_HOLD_PIN Pin = 23 -) - -// ESP32 coprocessor -const ( - ESP32_TXD_PIN Pin = 36 - ESP32_RXD_PIN Pin = 37 - ESP32_CTS_PIN Pin = 39 - ESP32_RTS_PIN Pin = 38 - ESP32_BOOT_MODE_PIN Pin = 16 - ESP32_WIFI_EN_PIN Pin = 24 - ESP32_HOST_WK_PIN Pin = 7 -) - -// Other peripherals -const ( - MODE_BUTTON_PIN Pin = 11 - CHARGE_STATUS_PIN Pin = 41 - LIPO_VOLTAGE_PIN Pin = 5 - PCB_ANTENNA_PIN Pin = 2 - EXTERNAL_UFL_PIN Pin = 25 - NFC1_PIN Pin = 9 - NFC2_PIN Pin = 10 -) - -// USB CDC identifiers -const ( - usb_STRING_PRODUCT = "Argon" - usb_STRING_MANUFACTURER = "Particle" -) - -var ( - usb_VID uint16 = 0x2B04 - usb_PID uint16 = 0xD00C -) diff --git a/emb/machine/board_particle_boron.go b/emb/machine/board_particle_boron.go deleted file mode 100644 index f986060..0000000 --- a/emb/machine/board_particle_boron.go +++ /dev/null @@ -1,109 +0,0 @@ -//go:build particle_boron - -package machine - -const HasLowFrequencyCrystal = true - -// More info: https://docs.particle.io/datasheets/cellular/boron-datasheet/ -// Board diagram: https://docs.particle.io/assets/images/boron/boron-block-diagram.png - -// GPIOs -const ( - A0 Pin = 3 - A1 Pin = 4 - A2 Pin = 28 - A3 Pin = 29 - A4 Pin = 30 - A5 Pin = 31 - D0 Pin = 26 // Also SDA - D1 Pin = 27 // Also SCL - D2 Pin = 33 - D3 Pin = 34 - D4 Pin = 40 - D5 Pin = 42 - D6 Pin = 43 - D7 Pin = 44 // Also LED - D8 Pin = 35 - D9 Pin = 6 // Also TX - D10 Pin = 8 // Also RX - D11 Pin = 46 // Also SDI - D12 Pin = 45 // Also SDO - D13 Pin = 47 // Also SCK -) - -// LEDs -const ( - LED Pin = 44 - LED_GREEN Pin = 14 - LED_RED Pin = 13 - LED_BLUE Pin = 15 -) - -// UART -var ( - DefaultUART = UART0 -) - -const ( - UART_TX_PIN Pin = 6 - UART_RX_PIN Pin = 8 -) - -// I2C pins -const ( - SDA_PIN Pin = 26 - SCL_PIN Pin = 27 - - // Internal I2C with MAX17043 (Fuel gauge) and BQ24195 (Power management) chips on it - SDA1_PIN Pin = 24 - SCL1_PIN Pin = 41 - INT1_PIN Pin = 5 -) - -// SPI pins -const ( - SPI0_SCK_PIN Pin = 47 - SPI0_SDO_PIN Pin = 45 - SPI0_SDI_PIN Pin = 46 -) - -// Internal 4MB SPI Flash -const ( - SPI1_SCK_PIN Pin = 19 - SPI1_SDO_PIN Pin = 20 - SPI1_SDI_PIN Pin = 21 - SPI1_CS_PIN Pin = 17 - SPI1_WP_PIN Pin = 22 - SPI1_HOLD_PIN Pin = 23 -) - -// u-blox SARA coprocessor -const ( - SARA_TXD_PIN Pin = 37 - SARA_RXD_PIN Pin = 36 - SARA_CTS_PIN Pin = 38 - SARA_RTS_PIN Pin = 39 - SARA_RESET_PIN Pin = 12 - SARA_POWER_ON_PIN Pin = 16 - SARA_BUFF_EN_PIN Pin = 25 - SARA_VINT_PIN Pin = 2 -) - -// Other peripherals -const ( - MODE_BUTTON_PIN Pin = 11 - ANTENNA_SEL_PIN Pin = 7 // Low: chip antenna, High: External uFL - NFC1_PIN Pin = 9 - NFC2_PIN Pin = 10 -) - -// USB CDC identifiers -const ( - usb_STRING_PRODUCT = "Boron" - usb_STRING_MANUFACTURER = "Particle" -) - -var ( - usb_VID uint16 = 0x2B04 - usb_PID uint16 = 0xD00D -) diff --git a/emb/machine/board_particle_xenon.go b/emb/machine/board_particle_xenon.go deleted file mode 100644 index 52c2b18..0000000 --- a/emb/machine/board_particle_xenon.go +++ /dev/null @@ -1,95 +0,0 @@ -//go:build particle_xenon - -package machine - -const HasLowFrequencyCrystal = true - -// More info: https://docs.particle.io/datasheets/discontinued/xenon-datasheet/ -// Board diagram: https://docs.particle.io/assets/images/xenon/xenon-block-diagram.png - -// GPIOs -const ( - A0 Pin = 3 - A1 Pin = 4 - A2 Pin = 28 - A3 Pin = 29 - A4 Pin = 30 - A5 Pin = 31 - D0 Pin = 26 // Also SDA - D1 Pin = 27 // Also SCL - D2 Pin = 33 - D3 Pin = 34 - D4 Pin = 40 - D5 Pin = 42 - D6 Pin = 43 - D7 Pin = 44 // Also LED - D8 Pin = 35 - D9 Pin = 6 // Also TX - D10 Pin = 8 // Also RX - D11 Pin = 46 // Also SDI - D12 Pin = 45 // Also SDO - D13 Pin = 47 // Also SCK -) - -// LEDs -const ( - LED Pin = 44 - LED_GREEN Pin = 14 - LED_RED Pin = 13 - LED_BLUE Pin = 15 -) - -// UART -var ( - DefaultUART = UART0 -) - -const ( - UART_TX_PIN Pin = 6 - UART_RX_PIN Pin = 8 -) - -// I2C pins -const ( - SDA_PIN Pin = 26 - SCL_PIN Pin = 27 -) - -// SPI pins -const ( - SPI0_SCK_PIN Pin = 47 - SPI0_SDO_PIN Pin = 45 - SPI0_SDI_PIN Pin = 46 -) - -// Internal 4MB SPI Flash -const ( - SPI1_SCK_PIN Pin = 19 - SPI1_SDO_PIN Pin = 20 - SPI1_SDI_PIN Pin = 21 - SPI1_CS_PIN Pin = 17 - SPI1_WP_PIN Pin = 22 - SPI1_HOLD_PIN Pin = 23 -) - -// Other peripherals -const ( - MODE_BUTTON_PIN Pin = 11 - CHARGE_STATUS_PIN Pin = 41 - LIPO_VOLTAGE_PIN Pin = 5 - PCB_ANTENNA_PIN Pin = 24 - EXTERNAL_UFL_PIN Pin = 25 - NFC1_PIN Pin = 9 - NFC2_PIN Pin = 10 -) - -// USB CDC identifiers -const ( - usb_STRING_PRODUCT = "Xenon" - usb_STRING_MANUFACTURER = "Particle" -) - -var ( - usb_VID uint16 = 0x2B04 - usb_PID uint16 = 0xD00E -) diff --git a/emb/machine/board_pca10031.go b/emb/machine/board_pca10031.go deleted file mode 100644 index 3d8f34f..0000000 --- a/emb/machine/board_pca10031.go +++ /dev/null @@ -1,41 +0,0 @@ -//go:build pca10031 - -// pca10031 is a nrf51 based dongle, intended for use in wireless applications. -// -// https://infocenter.nordicsemi.com/pdf/nRF51_Dongle_UG_v1.0.pdf -package machine - -// The pca10031 has a 32kHz crystal on board. -const HasLowFrequencyCrystal = true - -// LED on the pca10031 -const ( - LED1 = LED_RED - LED2 = LED_GREEN - LED3 = LED_BLUE - LED_RED = P0_21 - LED_GREEN = P0_22 - LED_BLUE = P0_23 - LED = LED_RED -) - -var DefaultUART = UART0 - -// UART pins -const ( - UART_TX_PIN = P0_09 - UART_RX_PIN = P0_11 -) - -// I2C pins (disabled) -const ( - SDA_PIN = NoPin - SCL_PIN = NoPin -) - -// SPI pins (unused) -const ( - SPI0_SCK_PIN = NoPin - SPI0_SDO_PIN = NoPin - SPI0_SDI_PIN = NoPin -) diff --git a/emb/machine/board_pca10040.go b/emb/machine/board_pca10040.go deleted file mode 100644 index a9be6ad..0000000 --- a/emb/machine/board_pca10040.go +++ /dev/null @@ -1,55 +0,0 @@ -//go:build pca10040 - -package machine - -// The PCA10040 has a low-frequency (32kHz) crystal oscillator on board. -const HasLowFrequencyCrystal = true - -// LEDs on the PCA10040 (nRF52832 dev board) -const ( - LED1 Pin = 17 - LED2 Pin = 18 - LED3 Pin = 19 - LED4 Pin = 20 - LED Pin = LED1 -) - -// Buttons on the PCA10040 (nRF52832 dev board) -const ( - BUTTON1 Pin = 13 - BUTTON2 Pin = 14 - BUTTON3 Pin = 15 - BUTTON4 Pin = 16 - BUTTON Pin = BUTTON1 -) - -var DefaultUART = UART0 - -// UART pins for NRF52840-DK -const ( - UART_TX_PIN Pin = 6 - UART_RX_PIN Pin = 8 -) - -// ADC pins -const ( - ADC0 Pin = 3 - ADC1 Pin = 4 - ADC2 Pin = 28 - ADC3 Pin = 29 - ADC4 Pin = 30 - ADC5 Pin = 31 -) - -// I2C pins -const ( - SDA_PIN Pin = 26 - SCL_PIN Pin = 27 -) - -// SPI pins -const ( - SPI0_SCK_PIN Pin = 25 - SPI0_SDO_PIN Pin = 23 - SPI0_SDI_PIN Pin = 24 -) diff --git a/emb/machine/board_pca10056.go b/emb/machine/board_pca10056.go deleted file mode 100644 index 44a2d53..0000000 --- a/emb/machine/board_pca10056.go +++ /dev/null @@ -1,65 +0,0 @@ -//go:build pca10056 - -package machine - -const HasLowFrequencyCrystal = true - -// LEDs on the pca10056 -const ( - LED1 Pin = 13 - LED2 Pin = 14 - LED3 Pin = 15 - LED4 Pin = 16 - LED Pin = LED1 -) - -// Buttons on the pca10056 -const ( - BUTTON1 Pin = 11 - BUTTON2 Pin = 12 - BUTTON3 Pin = 24 - BUTTON4 Pin = 25 - BUTTON Pin = BUTTON1 -) - -var DefaultUART = UART0 - -// UART pins -const ( - UART_TX_PIN Pin = 6 - UART_RX_PIN Pin = 8 -) - -// ADC pins -const ( - ADC0 Pin = 3 - ADC1 Pin = 4 - ADC2 Pin = 28 - ADC3 Pin = 29 - ADC4 Pin = 30 - ADC5 Pin = 31 -) - -// I2C pins -const ( - SDA_PIN Pin = 26 // P0.26 - SCL_PIN Pin = 27 // P0.27 -) - -// SPI pins -const ( - SPI0_SCK_PIN Pin = 47 // P1.15 - SPI0_SDO_PIN Pin = 45 // P1.13 - SPI0_SDI_PIN Pin = 46 // P1.14 -) - -// USB CDC identifiers -const ( - usb_STRING_PRODUCT = "Nordic nRF52840DK (PCA10056)" - usb_STRING_MANUFACTURER = "Nordic Semiconductor" -) - -var ( - usb_VID uint16 = 0x239A - usb_PID uint16 = 0x8029 -) diff --git a/emb/machine/board_pca10059.go b/emb/machine/board_pca10059.go deleted file mode 100644 index bd11503..0000000 --- a/emb/machine/board_pca10059.go +++ /dev/null @@ -1,59 +0,0 @@ -//go:build pca10059 - -package machine - -// The PCA10040 has a low-frequency (32kHz) crystal oscillator on board. -const HasLowFrequencyCrystal = true - -// LEDs on the PCA10059 (nRF52840 dongle) -const ( - LED1 Pin = 6 - LED2 Pin = 8 - LED3 Pin = (1 << 5) | 9 - LED4 Pin = 12 - LED Pin = LED1 -) - -// Buttons on the PCA10059 (nRF52840 dongle) -const ( - BUTTON1 Pin = (1 << 5) | 6 - BUTTON Pin = BUTTON1 -) - -// ADC pins -const ( - ADC1 Pin = 2 - ADC2 Pin = 4 - ADC3 Pin = 29 - ADC4 Pin = 31 -) - -// UART pins -const ( - UART_TX_PIN Pin = NoPin - UART_RX_PIN Pin = NoPin -) - -// I2C pins (unused) -const ( - SDA_PIN = NoPin - SCL_PIN = NoPin -) - -// SPI pins (unused) -const ( - SPI0_SCK_PIN = NoPin - SPI0_SDO_PIN = NoPin - SPI0_SDI_PIN = NoPin -) - -// USB CDC identifiers -const ( - usb_STRING_PRODUCT = "nRF52840 Dongle" - usb_STRING_MANUFACTURER = "Nordic Semiconductor ASA" -) - -var ( - usb_VID uint16 = 0x1915 - usb_PID uint16 = 0xCAFE -) diff --git a/emb/machine/board_pga2350.go b/emb/machine/board_pga2350.go deleted file mode 100644 index 710f14d..0000000 --- a/emb/machine/board_pga2350.go +++ /dev/null @@ -1,98 +0,0 @@ -//go:build pga2350 - -package machine - -// PGA2350 pin definitions. -const ( - GP0 = GPIO0 - GP1 = GPIO1 - GP2 = GPIO2 - GP3 = GPIO3 - GP4 = GPIO4 - GP5 = GPIO5 - GP6 = GPIO6 - GP7 = GPIO7 - GP8 = GPIO8 - GP9 = GPIO9 - GP10 = GPIO10 - GP11 = GPIO11 - GP12 = GPIO12 - GP13 = GPIO13 - GP14 = GPIO14 - GP15 = GPIO15 - GP16 = GPIO16 - GP17 = GPIO17 - GP18 = GPIO18 - GP19 = GPIO19 - GP20 = GPIO20 - GP21 = GPIO21 - GP22 = GPIO22 - GP26 = GPIO26 - GP27 = GPIO27 - GP28 = GPIO28 - GP29 = GPIO29 - GP30 = GPIO30 // peripherals: PWM7 channel A - GP31 = GPIO31 // peripherals: PWM7 channel B - GP32 = GPIO32 // peripherals: PWM8 channel A - GP33 = GPIO33 // peripherals: PWM8 channel B - GP34 = GPIO34 // peripherals: PWM9 channel A - GP35 = GPIO35 // peripherals: PWM9 channel B - GP36 = GPIO36 // peripherals: PWM10 channel A - GP37 = GPIO37 // peripherals: PWM10 channel B - GP38 = GPIO38 // peripherals: PWM11 channel A - GP39 = GPIO39 // peripherals: PWM11 channel B - GP40 = GPIO40 // peripherals: PWM8 channel A - GP41 = GPIO41 // peripherals: PWM8 channel B - GP42 = GPIO42 // peripherals: PWM9 channel A - GP43 = GPIO43 // peripherals: PWM9 channel B - GP44 = GPIO44 // peripherals: PWM10 channel A - GP45 = GPIO45 // peripherals: PWM10 channel B - GP46 = GPIO46 // peripherals: PWM11 channel A - GP47 = GPIO47 // peripherals: PWM11 channel B - -) - -var DefaultUART = UART0 - -// Peripheral defaults. -const ( - xoscFreq = 12 // MHz - - I2C0_SDA_PIN = GP4 - I2C0_SCL_PIN = GP5 - - I2C1_SDA_PIN = GP2 - I2C1_SCL_PIN = GP3 - - // Default Serial Clock Bus 0 for SPI communications - SPI0_SCK_PIN = GPIO18 - // Default Serial Out Bus 0 for SPI communications - SPI0_SDO_PIN = GPIO19 // Tx - // Default Serial In Bus 0 for SPI communications - SPI0_SDI_PIN = GPIO16 // Rx - - // Default Serial Clock Bus 1 for SPI communications - SPI1_SCK_PIN = GPIO10 - // Default Serial Out Bus 1 for SPI communications - SPI1_SDO_PIN = GPIO11 // Tx - // Default Serial In Bus 1 for SPI communications - SPI1_SDI_PIN = GPIO12 // Rx - - UART0_TX_PIN = GPIO0 - UART0_RX_PIN = GPIO1 - UART1_TX_PIN = GPIO8 - UART1_RX_PIN = GPIO9 - UART_TX_PIN = UART0_TX_PIN - UART_RX_PIN = UART0_RX_PIN -) - -// USB identifiers -const ( - usb_STRING_PRODUCT = "PGA2350" - usb_STRING_MANUFACTURER = "Pimoroni" -) - -var ( - usb_VID uint16 = 0x2E8A - usb_PID uint16 = 0x000A -) diff --git a/emb/machine/board_pico.go b/emb/machine/board_pico.go deleted file mode 100644 index efbd6ef..0000000 --- a/emb/machine/board_pico.go +++ /dev/null @@ -1,88 +0,0 @@ -//go:build pico - -package machine - -// GPIO pins -const ( - GP0 Pin = GPIO0 - GP1 Pin = GPIO1 - GP2 Pin = GPIO2 - GP3 Pin = GPIO3 - GP4 Pin = GPIO4 - GP5 Pin = GPIO5 - GP6 Pin = GPIO6 - GP7 Pin = GPIO7 - GP8 Pin = GPIO8 - GP9 Pin = GPIO9 - GP10 Pin = GPIO10 - GP11 Pin = GPIO11 - GP12 Pin = GPIO12 - GP13 Pin = GPIO13 - GP14 Pin = GPIO14 - GP15 Pin = GPIO15 - GP16 Pin = GPIO16 - GP17 Pin = GPIO17 - GP18 Pin = GPIO18 - GP19 Pin = GPIO19 - GP20 Pin = GPIO20 - GP21 Pin = GPIO21 - GP22 Pin = GPIO22 - GP26 Pin = GPIO26 - GP27 Pin = GPIO27 - GP28 Pin = GPIO28 - - // Onboard LED - LED Pin = GPIO25 - - // Onboard crystal oscillator frequency, in MHz. - xoscFreq = 12 // MHz -) - -// I2C Default pins on Raspberry Pico. -const ( - I2C0_SDA_PIN = GP4 - I2C0_SCL_PIN = GP5 - - I2C1_SDA_PIN = GP2 - I2C1_SCL_PIN = GP3 -) - -// SPI default pins -const ( - // Default Serial Clock Bus 0 for SPI communications - SPI0_SCK_PIN = GPIO18 - // Default Serial Out Bus 0 for SPI communications - SPI0_SDO_PIN = GPIO19 // Tx - // Default Serial In Bus 0 for SPI communications - SPI0_SDI_PIN = GPIO16 // Rx - - // Default Serial Clock Bus 1 for SPI communications - SPI1_SCK_PIN = GPIO10 - // Default Serial Out Bus 1 for SPI communications - SPI1_SDO_PIN = GPIO11 // Tx - // Default Serial In Bus 1 for SPI communications - SPI1_SDI_PIN = GPIO12 // Rx -) - -// UART pins -const ( - UART0_TX_PIN = GPIO0 - UART0_RX_PIN = GPIO1 - UART1_TX_PIN = GPIO8 - UART1_RX_PIN = GPIO9 - UART_TX_PIN = UART0_TX_PIN - UART_RX_PIN = UART0_RX_PIN -) - -var DefaultUART = UART0 - -// USB identifiers -const ( - usb_STRING_PRODUCT = "Pico" - usb_STRING_MANUFACTURER = "Raspberry Pi" -) - -var ( - usb_VID uint16 = 0x2E8A - usb_PID uint16 = 0x000A -) diff --git a/emb/machine/board_pico2.go b/emb/machine/board_pico2.go deleted file mode 100644 index 327c542..0000000 --- a/emb/machine/board_pico2.go +++ /dev/null @@ -1,88 +0,0 @@ -//go:build pico2 - -package machine - -// GPIO pins -const ( - GP0 Pin = GPIO0 - GP1 Pin = GPIO1 - GP2 Pin = GPIO2 - GP3 Pin = GPIO3 - GP4 Pin = GPIO4 - GP5 Pin = GPIO5 - GP6 Pin = GPIO6 - GP7 Pin = GPIO7 - GP8 Pin = GPIO8 - GP9 Pin = GPIO9 - GP10 Pin = GPIO10 - GP11 Pin = GPIO11 - GP12 Pin = GPIO12 - GP13 Pin = GPIO13 - GP14 Pin = GPIO14 - GP15 Pin = GPIO15 - GP16 Pin = GPIO16 - GP17 Pin = GPIO17 - GP18 Pin = GPIO18 - GP19 Pin = GPIO19 - GP20 Pin = GPIO20 - GP21 Pin = GPIO21 - GP22 Pin = GPIO22 - GP26 Pin = GPIO26 - GP27 Pin = GPIO27 - GP28 Pin = GPIO28 - - // Onboard LED - LED Pin = GPIO25 - - // Onboard crystal oscillator frequency, in MHz. - xoscFreq = 12 // MHz -) - -// I2C Default pins on Raspberry Pico. -const ( - I2C0_SDA_PIN = GP4 - I2C0_SCL_PIN = GP5 - - I2C1_SDA_PIN = GP2 - I2C1_SCL_PIN = GP3 -) - -// SPI default pins -const ( - // Default Serial Clock Bus 0 for SPI communications - SPI0_SCK_PIN = GPIO18 - // Default Serial Out Bus 0 for SPI communications - SPI0_SDO_PIN = GPIO19 // Tx - // Default Serial In Bus 0 for SPI communications - SPI0_SDI_PIN = GPIO16 // Rx - - // Default Serial Clock Bus 1 for SPI communications - SPI1_SCK_PIN = GPIO10 - // Default Serial Out Bus 1 for SPI communications - SPI1_SDO_PIN = GPIO11 // Tx - // Default Serial In Bus 1 for SPI communications - SPI1_SDI_PIN = GPIO12 // Rx -) - -// UART pins -const ( - UART0_TX_PIN = GPIO0 - UART0_RX_PIN = GPIO1 - UART1_TX_PIN = GPIO8 - UART1_RX_PIN = GPIO9 - UART_TX_PIN = UART0_TX_PIN - UART_RX_PIN = UART0_RX_PIN -) - -var DefaultUART = UART0 - -// USB identifiers -const ( - usb_STRING_PRODUCT = "Pico2" - usb_STRING_MANUFACTURER = "Raspberry Pi" -) - -var ( - usb_VID uint16 = 0x2E8A - usb_PID uint16 = 0x000A -) diff --git a/emb/machine/board_pico_plus2.go b/emb/machine/board_pico_plus2.go deleted file mode 100644 index c21c9ea..0000000 --- a/emb/machine/board_pico_plus2.go +++ /dev/null @@ -1,93 +0,0 @@ -//go:build pico_plus2 - -package machine - -// GPIO pins -const ( - GP0 Pin = GPIO0 - GP1 Pin = GPIO1 - GP2 Pin = GPIO2 - GP3 Pin = GPIO3 - GP4 Pin = GPIO4 - GP5 Pin = GPIO5 - GP6 Pin = GPIO6 - GP7 Pin = GPIO7 - GP8 Pin = GPIO8 - GP9 Pin = GPIO9 - GP10 Pin = GPIO10 - GP11 Pin = GPIO11 - GP12 Pin = GPIO12 - GP13 Pin = GPIO13 - GP14 Pin = GPIO14 - GP15 Pin = GPIO15 - GP16 Pin = GPIO16 - GP17 Pin = GPIO17 - GP18 Pin = GPIO18 - GP19 Pin = GPIO19 - GP20 Pin = GPIO20 - GP21 Pin = GPIO21 - GP22 Pin = GPIO22 - GP26 Pin = GPIO26 - GP27 Pin = GPIO27 - GP28 Pin = GPIO28 - GP32 Pin = GPIO32 - GP33 Pin = GPIO33 - GP34 Pin = GPIO34 - GP35 Pin = GPIO35 - GP36 Pin = GPIO36 - - // Onboard LED - LED Pin = GPIO25 - - // Onboard crystal oscillator frequency, in MHz. - xoscFreq = 12 // MHz -) - -// I2C Default pins on Raspberry Pico. -const ( - I2C0_SDA_PIN = GP4 - I2C0_SCL_PIN = GP5 - - I2C1_SDA_PIN = GP2 - I2C1_SCL_PIN = GP3 -) - -// SPI default pins -const ( - // Default Serial Clock Bus 0 for SPI communications - SPI0_SCK_PIN = GPIO18 - // Default Serial Out Bus 0 for SPI communications - SPI0_SDO_PIN = GPIO19 // Tx - // Default Serial In Bus 0 for SPI communications - SPI0_SDI_PIN = GPIO16 // Rx - - // Default Serial Clock Bus 1 for SPI communications - SPI1_SCK_PIN = GPIO10 - // Default Serial Out Bus 1 for SPI communications - SPI1_SDO_PIN = GPIO11 // Tx - // Default Serial In Bus 1 for SPI communications - SPI1_SDI_PIN = GPIO12 // Rx -) - -// UART pins -const ( - UART0_TX_PIN = GPIO0 - UART0_RX_PIN = GPIO1 - UART1_TX_PIN = GPIO8 - UART1_RX_PIN = GPIO9 - UART_TX_PIN = UART0_TX_PIN - UART_RX_PIN = UART0_RX_PIN -) - -var DefaultUART = UART0 - -// USB identifiers -const ( - usb_STRING_PRODUCT = "Pico Plus2" - usb_STRING_MANUFACTURER = "Pimoroni" -) - -var ( - usb_VID uint16 = 0x2E8A - usb_PID uint16 = 0x000F -) diff --git a/emb/machine/board_pinetime.go b/emb/machine/board_pinetime.go deleted file mode 100644 index f7a137b..0000000 --- a/emb/machine/board_pinetime.go +++ /dev/null @@ -1,60 +0,0 @@ -//go:build pinetime - -package machine - -// Board pins for the PineTime. -// Details: https://wiki.pine64.org/index.php/PineTime - -// The PineTime has a low-frequency (32kHz) crystal oscillator on board. -const HasLowFrequencyCrystal = true - -// LEDs simply expose the three brightness level LEDs on the PineTime. They can -// be useful for simple "hello world" style programs. -const ( - LED1 = LCD_BACKLIGHT_HIGH - LED2 = LCD_BACKLIGHT_MID - LED3 = LCD_BACKLIGHT_LOW - LED = LED1 -) - -// The PineTime doesn't have a UART output. -// Additionally, leaving the UART on results in a pretty big current drain. -const ( - UART_TX_PIN Pin = NoPin - UART_RX_PIN Pin = NoPin -) - -// SPI pins for the PineTime. -const ( - SPI0_SCK_PIN Pin = 2 - SPI0_SDO_PIN Pin = 3 - SPI0_SDI_PIN Pin = 4 -) - -// I2C pins for the PineTime. -const ( - SDA_PIN Pin = 6 - SCL_PIN Pin = 7 -) - -// Button pins. For some reason, there are two pins for the button. -const ( - BUTTON_IN Pin = 13 - BUTTON_OUT Pin = 15 -) - -// Pin for the vibrator. -const VIBRATOR_PIN Pin = 16 - -// LCD pins, using the naming convention of the official docs: -// http://files.pine64.org/doc/PineTime/PineTime%20Port%20Assignment%20rev1.0.pdf -const ( - LCD_SCK = SPI0_SCK_PIN - LCD_SDI = SPI0_SDO_PIN - LCD_RS Pin = 18 - LCD_CS Pin = 25 - LCD_RESET Pin = 26 - LCD_BACKLIGHT_LOW Pin = 14 - LCD_BACKLIGHT_MID Pin = 22 - LCD_BACKLIGHT_HIGH Pin = 23 -) diff --git a/emb/machine/board_pybadge.go b/emb/machine/board_pybadge.go deleted file mode 100644 index 30d44d1..0000000 --- a/emb/machine/board_pybadge.go +++ /dev/null @@ -1,162 +0,0 @@ -//go:build pybadge - -package machine - -// used to reset into bootloader -const resetMagicValue = 0xf01669ef - -// GPIO Pins -const ( - D0 = PB17 // UART0 RX/PWM available - D1 = PB16 // UART0 TX/PWM available - D2 = PB03 - D3 = PB02 - D4 = PA14 // PWM available - D5 = PA16 // PWM available - D6 = PA18 // PWM available - D7 = PB14 - D8 = PA15 // built-in neopixel - D9 = PA19 // PWM available - D10 = PA20 // can be used for PWM or UART1 TX - D11 = PA21 // can be used for PWM or UART1 RX - D12 = PA22 // PWM available - D13 = PA23 // PWM available -) - -// Analog pins -const ( - A0 = PA02 // ADC/AIN[0] - A1 = PA05 // ADC/AIN[2] - A2 = PB08 // ADC/AIN[3] - A3 = PB09 // ADC/AIN[4] - A4 = PA04 // ADC/AIN[5] - A5 = PA06 // ADC/AIN[6] - A6 = PB01 // ADC/AIN[12]/VMEAS - A7 = PB04 // ADC/AIN[6]/LIGHT - A8 = D2 // ADC/AIN[14] - A9 = D3 // ADC/AIN[15] -) - -const ( - LED = D13 - NEOPIXELS = D8 - WS2812 = D8 - - LIGHTSENSOR = A7 - - BUTTON_LATCH = PB00 - BUTTON_OUT = PB30 - BUTTON_CLK = PB31 - - TFT_DC = PB05 - TFT_CS = PB07 - TFT_RST = PA00 - TFT_LITE = PA01 - - SPEAKER_ENABLE = PA27 -) - -const ( - BUTTON_LEFT_MASK = 1 - BUTTON_UP_MASK = 2 - BUTTON_DOWN_MASK = 4 - BUTTON_RIGHT_MASK = 8 - BUTTON_SELECT_MASK = 16 - BUTTON_START_MASK = 32 - BUTTON_A_MASK = 64 - BUTTON_B_MASK = 128 -) - -// USBCDC pins -const ( - USBCDC_DM_PIN = PA24 - USBCDC_DP_PIN = PA25 -) - -// UART1 pins -const ( - UART_TX_PIN = D1 - UART_RX_PIN = D0 -) - -const ( - UART2_TX_PIN = A4 - UART2_RX_PIN = A5 -) - -var ( - UART1 = &sercomUSART5 - UART2 = &sercomUSART0 - - DefaultUART = UART1 -) - -// I2C pins -const ( - SDA_PIN = PA12 // SDA: SERCOM2/PAD[0] - SCL_PIN = PA13 // SCL: SERCOM2/PAD[1] -) - -// I2C on the ItsyBitsy M4. -var I2C0 = sercomI2CM2 - -// SPI pins -const ( - SPI0_SCK_PIN = PA17 // SCK: SERCOM1/PAD[1] - SPI0_SDO_PIN = PB23 // SDO: SERCOM1/PAD[3] - SPI0_SDI_PIN = PB22 // SDI: SERCOM1/PAD[2] -) - -// TFT SPI pins -const ( - SPI1_SCK_PIN = PB13 // SCK: SERCOM4/PAD[1] - SPI1_SDO_PIN = PB15 // SDO: SERCOM4/PAD[3] - SPI1_SDI_PIN = NoPin -) - -// SPI on the PyBadge. -var SPI0 = sercomSPIM1 - -// TFT SPI on the PyBadge. -var SPI1 = sercomSPIM4 - -// USB CDC identifiers -const ( - usb_STRING_PRODUCT = "Adafruit pyBadge M4" - usb_STRING_MANUFACTURER = "Adafruit" -) - -var ( - usb_VID uint16 = 0x239A - usb_PID uint16 = 0x8033 -) - -// NINA-W102 settings when using AirLift WiFi FeatherWing -const ( - NINA_BAUDRATE = 115200 - NINA_RESET_INVERTED = true - NINA_SOFT_FLOWCONTROL = true -) - -const ( - NINA_CS = D13 - NINA_ACK = D11 - NINA_GPIO0 = D10 - NINA_RESETN = D12 - - // pins used for the ESP32 connection do not allow hardware - // flow control, which is required. have to emulate with software. - NINA_TX = UART_TX_PIN - NINA_RX = UART_RX_PIN - NINA_CTS = NINA_ACK - NINA_RTS = NINA_GPIO0 - - NINA_SDO = SPI0_SDO_PIN - NINA_SDI = SPI0_SDI_PIN - NINA_SCK = SPI0_SCK_PIN -) - -var ( - NINA_SPI = SPI0 - UART_NINA = UART1 -) diff --git a/emb/machine/board_pygamer.go b/emb/machine/board_pygamer.go deleted file mode 100644 index 84a7464..0000000 --- a/emb/machine/board_pygamer.go +++ /dev/null @@ -1,133 +0,0 @@ -//go:build sam && atsamd51 && pygamer - -package machine - -// used to reset into bootloader -const resetMagicValue = 0xf01669ef - -// GPIO Pins -const ( - D0 = PB17 // UART0 RX/PWM available - D1 = PB16 // UART0 TX/PWM available - D2 = PB03 - D3 = PB02 - D4 = PA14 // PWM available - D5 = PA16 // PWM available - D6 = PA18 // PWM available - D7 = PB14 // CS for microSD card slot - D8 = PA15 // built-in neopixel - D9 = PA19 // PWM available - D10 = PA20 // can be used for PWM or UART1 TX - D11 = PA21 // can be used for PWM or UART1 RX - D12 = PA22 // PWM available - D13 = PA23 // PWM available -) - -// Analog pins -const ( - A0 = PA02 // ADC/AIN[0] - A1 = PA05 // ADC/AIN[2] - A2 = PB08 // ADC/AIN[3] - A3 = PB09 // ADC/AIN[4] - A4 = PA04 // ADC/AIN[5] - A5 = PA06 // ADC/AIN[6] - A6 = PB01 // ADC/AIN[12]/VMEAS - A7 = PB04 // ADC/AIN[6]/LIGHT - A8 = D2 // ADC/AIN[14] - A9 = D3 // ADC/AIN[15] -) - -const ( - LED = D13 - NEOPIXELS = D8 - WS2812 = D8 - - SD_CS = D7 - - LIGHTSENSOR = A7 - - BUTTON_LATCH = PB00 - BUTTON_OUT = PB30 - BUTTON_CLK = PB31 - - JOYY = PB06 - JOYX = PB07 - - TFT_DC = PB05 - TFT_CS = PB12 - TFT_RST = PA00 - TFT_LITE = PA01 - - SPEAKER_ENABLE = PA27 -) - -const ( - BUTTON_SELECT_MASK = 16 - BUTTON_START_MASK = 32 - BUTTON_A_MASK = 64 - BUTTON_B_MASK = 128 -) - -// USBCDC pins -const ( - USBCDC_DM_PIN = PA24 - USBCDC_DP_PIN = PA25 -) - -// UART1 pins -const ( - UART_TX_PIN = D1 - UART_RX_PIN = D0 -) - -// UART1 var is on SERCOM3, defined in atsamd51.go - -// UART2 pins -const ( - UART2_TX_PIN = A4 - UART2_RX_PIN = A5 -) - -// UART2 var is on SERCOM0, defined in atsamd51.go - -// I2C pins -const ( - SDA_PIN = PA12 // SDA: SERCOM2/PAD[0] - SCL_PIN = PA13 // SCL: SERCOM2/PAD[1] -) - -// I2C on the PyGamer. -var ( - I2C0 = sercomI2CM2 -) - -// SPI pins -const ( - SPI0_SCK_PIN = PA17 // SCK: SERCOM1/PAD[1] - SPI0_SDO_PIN = PB23 // SDO: SERCOM1/PAD[3] - SPI0_SDI_PIN = PB22 // SDI: SERCOM1/PAD[2] -) - -// SPI on the PyGamer. -var SPI0 = sercomSPIM1 - -// TFT SPI pins -const ( - SPI1_SCK_PIN = PB13 // SCK: SERCOM4/PAD[1] - SPI1_SDO_PIN = PB15 // SDO: SERCOM4/PAD[3] - SPI1_SDI_PIN = NoPin -) - -// TFT SPI on the PyGamer. -var SPI1 = sercomSPIM4 - -// USB CDC identifiers -const ( - usb_STRING_PRODUCT = "Adafruit pyGamer M4" - usb_STRING_MANUFACTURER = "Adafruit" -) - -var ( - usb_VID uint16 = 0x239A - usb_PID uint16 = 0x8033 -) diff --git a/emb/machine/board_pyportal.go b/emb/machine/board_pyportal.go deleted file mode 100644 index 98ef01d..0000000 --- a/emb/machine/board_pyportal.go +++ /dev/null @@ -1,165 +0,0 @@ -//go:build pyportal - -package machine - -// used to reset into bootloader -const resetMagicValue = 0xf01669ef - -// GPIO Pins -const ( - D0 = PB13 // NINA_RX - D1 = PB12 // NINA_TX - D2 = PB22 // built-in neopixel - D3 = PA04 // PWM available - D4 = PA05 // PWM available - D5 = PB16 // NINA_ACK - D6 = PB15 // NINA_GPIO0 - D7 = PB17 // NINA_RESETN - D8 = PB14 // NINA_CS - D9 = PB04 // TFT_RD - D10 = PB05 // TFT_DC - D11 = PB06 // TFT_CS - D12 = PB07 // TFT_TE - D13 = PB23 // built-in LED - D24 = PA00 // TFT_RESET - D25 = PB31 // TFT_BACKLIGHT - D26 = PB09 // TFT_WR - D27 = PB02 // SDA - D28 = PB03 // SCL - D29 = PA12 // SDO - D30 = PA13 // SCK - D31 = PA14 // SDI - D32 = PB30 // SD_CS - D33 = PA01 // SD_CARD_DETECT - D34 = PA16 // LCD_DATA0 - D35 = PA17 // LCD_DATA1 - D36 = PA18 // LCD_DATA2 - D37 = PA19 // LCD_DATA3 - D38 = PA20 // LCD_DATA4 - D39 = PA21 // LCD_DATA5 - D40 = PA22 // LCD_DATA6 - D41 = PA23 // LCD_DATA7 - D42 = PB10 // QSPI - D43 = PB11 // QSPI - D44 = PA08 // QSPI - D45 = PA09 // QSPI - D46 = PA10 // QSPI - D47 = PA11 // QSPI - D50 = PA02 // speaker amplifier shutdown - D51 = PA15 // NINA_RTS - - NINA_CS = D8 - NINA_ACK = D5 - NINA_GPIO0 = D6 - NINA_RESETN = D7 - - // pins used for the ESP32 connection do not allow hardware - // flow control, which is required. have to emulate with software. - NINA_TX = D1 - NINA_RX = D0 - NINA_CTS = NINA_ACK - NINA_RTS = NINA_GPIO0 - - LCD_DATA0 = D34 - - TFT_RD = D9 - TFT_DC = D10 - TFT_CS = D11 - TFT_TE = D12 - TFT_RESET = D24 - TFT_BACKLIGHT = D25 - TFT_WR = D26 - - NEOPIXEL = D2 - WS2812 = D2 - SPK_SD = D50 -) - -// Analog pins -const ( - A0 = PA02 // ADC0/AIN[0] - A1 = D3 // ADC0/AIN[4] - A2 = PA07 // ADC0/AIN[7] - A3 = D4 // ADC0/AIN[5] - A4 = PB00 // ADC0/AIN[12] - A5 = PB01 // ADC0/AIN[13] - A6 = PA06 // ADC0/AIN[6] - A7 = PB08 // ADC1/AIN[0] - - AUDIO_OUT = A0 - LIGHT = A2 - TOUCH_YD = A4 - TOUCH_XL = A5 - TOUCH_YU = A6 - TOUCH_XR = A7 -) - -const ( - LED = D13 -) - -// USBCDC pins -const ( - USBCDC_DM_PIN = PA24 - USBCDC_DP_PIN = PA25 -) - -// UART1 aka NINA_TX/NINA_RX -const ( - UART_TX_PIN = D1 - UART_RX_PIN = D0 -) - -var ( - UART1 = &sercomUSART4 - - DefaultUART = UART1 - - UART_NINA = UART1 -) - -// NINA-W102 settings -const ( - NINA_BAUDRATE = 115200 - NINA_RESET_INVERTED = true - NINA_SOFT_FLOWCONTROL = true -) - -// I2C pins -const ( - SDA_PIN = PB02 // SDA: SERCOM2/PAD[0] - SCL_PIN = PB03 // SCL: SERCOM2/PAD[1] -) - -// I2C on the PyPortal. -var ( - I2C0 = sercomI2CM5 -) - -// SPI pins -const ( - SPI0_SCK_PIN = PA13 // SCK: SERCOM1/PAD[1] - SPI0_SDO_PIN = PA12 // SDO: SERCOM1/PAD[3] - SPI0_SDI_PIN = PA14 // SDI: SERCOM1/PAD[2] - - NINA_SDO = SPI0_SDO_PIN - NINA_SDI = SPI0_SDI_PIN - NINA_SCK = SPI0_SCK_PIN -) - -// SPI on the PyPortal. -var ( - SPI0 = sercomSPIM2 - NINA_SPI = SPI0 -) - -// USB CDC identifiers -const ( - usb_STRING_PRODUCT = "Adafruit PyPortal M4" - usb_STRING_MANUFACTURER = "Adafruit" -) - -var ( - usb_VID uint16 = 0x239A - usb_PID uint16 = 0x8035 -) diff --git a/emb/machine/board_qtpy.go b/emb/machine/board_qtpy.go deleted file mode 100644 index e8a93e3..0000000 --- a/emb/machine/board_qtpy.go +++ /dev/null @@ -1,102 +0,0 @@ -//go:build sam && atsamd21 && qtpy - -package machine - -// used to reset into bootloader -const resetMagicValue = 0xf01669ef - -// GPIO Pins -const ( - D0 = PA02 // PWM available - D1 = PA03 - D2 = PA04 // PWM available - D3 = PA05 // PWM available - D4 = PA16 // PWM available - D5 = PA17 // PWM available - D6 = PA06 - D7 = PA07 - D8 = PA11 - D9 = PA09 - D10 = PA10 - D11 = PA18 - D12 = PA15 - D13 = PA27 - D14 = PA23 - D15 = PA19 - D16 = PA22 - D17 = PA08 -) - -// Analog pins -const ( - A0 = D0 - A1 = D1 - A2 = D2 - A3 = D3 - A4 = D4 -) - -const ( - NEOPIXELS = D11 - WS2812 = D11 - NEOPIXELS_POWER = D12 -) - -// USBCDC pins -const ( - USBCDC_DM_PIN = PA24 - USBCDC_DP_PIN = PA25 -) - -// UART1 pins -const ( - UART_TX_PIN = D6 - UART_RX_PIN = D7 -) - -// UART1 on the QT Py M0. -var UART1 = &sercomUSART0 - -// SPI pins -const ( - SPI0_SCK_PIN = D8 - SPI0_SDO_PIN = D10 - SPI0_SDI_PIN = D9 -) - -// SPI on the QT Py M0. -var SPI0 = sercomSPIM0 - -// I2C pins -const ( - SDA_PIN = D4 // SDA - SCL_PIN = D5 // SCL -) - -// I2C on the QT Py M0. -var ( - I2C0 = sercomI2CM1 -) - -// I2S pins -const ( - I2S_SCK_PIN = PA10 - I2S_SDO_PIN = PA08 - I2S_SDI_PIN = NoPin // TODO: figure out what this is on QT Py M0. - I2S_WS_PIN = NoPin // TODO: figure out what this is on QT Py M0. -) - -// USB CDC identifiers -const ( - usb_STRING_PRODUCT = "Adafruit QTPy M0" - usb_STRING_MANUFACTURER = "Adafruit" -) - -var ( - usb_VID uint16 = 0x239A - usb_PID uint16 = 0x80CB -) - -var ( - DefaultUART = UART1 -) diff --git a/emb/machine/board_qtpy_esp32c3.go b/emb/machine/board_qtpy_esp32c3.go deleted file mode 100644 index a2e3f48..0000000 --- a/emb/machine/board_qtpy_esp32c3.go +++ /dev/null @@ -1,60 +0,0 @@ -//go:build qtpy_esp32c3 - -// This file contains the pin mappings for the Adafruit QtPy ESP32C3 boards. -// -// https://learn.adafruit.com/adafruit-qt-py-esp32-c3-wifi-dev-board/pinouts -package machine - -// Digital Pins -const ( - D0 = GPIO4 - D1 = GPIO3 - D2 = GPIO1 - D3 = GPIO0 -) - -// Analog pins (ADC1) -const ( - A0 = GPIO4 - A1 = GPIO3 - A2 = GPIO1 - A3 = GPIO0 -) - -// UART pins -const ( - RX_PIN = GPIO20 - TX_PIN = GPIO21 - - UART_RX_PIN = RX_PIN - UART_TX_PIN = TX_PIN -) - -// I2C pins -const ( - SDA_PIN = GPIO5 - SCL_PIN = GPIO6 - - I2C0_SDA_PIN = SDA_PIN - I2C0_SCL_PIN = SCL_PIN -) - -// SPI pins -const ( - SCK_PIN = GPIO10 - MI_PIN = GPIO8 - MO_PIN = GPIO7 - - SPI_SCK_PIN = SCK_PIN - SPI_SDI_PIN = MI_PIN - SPI_SDO_PIN = MO_PIN -) - -const ( - NEOPIXEL = GPIO2 - WS2812 = GPIO2 - - // also used for boot button. - // set it to be an input-with-pullup - BUTTON = GPIO9 -) diff --git a/emb/machine/board_qtpy_rp2040.go b/emb/machine/board_qtpy_rp2040.go deleted file mode 100644 index 3eabf0c..0000000 --- a/emb/machine/board_qtpy_rp2040.go +++ /dev/null @@ -1,93 +0,0 @@ -//go:build qtpy_rp2040 - -package machine - -// Onboard crystal oscillator frequency, in MHz. -const xoscFreq = 12 // MHz - -// GPIO Pins -const ( - SDA = GPIO24 - SCL = GPIO25 - TX = GPIO20 - MO = GPIO3 - MOSI = GPIO3 - MI = GPIO4 - MISO = GPIO4 - SCK = GPIO6 - RX = GPIO5 - - QT_SCL1 = GPIO23 - QT_SDA1 = GPIO22 -) - -// Analog pins -const ( - A0 = GPIO29 - A1 = GPIO28 - A2 = GPIO27 - A3 = GPIO26 -) - -const ( - NEOPIXEL = GPIO12 - WS2812 = GPIO12 - NEOPIXEL_POWER = GPIO11 -) - -// I2C Pins. -const ( - I2C0_SDA_PIN = GPIO24 - I2C0_SCL_PIN = GPIO25 - - I2C1_SDA_PIN = GPIO26 - I2C1_SCL_PIN = GPIO27 - - I2C1_QT_SDA_PIN = GPIO22 - I2C1_QT_SCL_PIN = GPIO23 - - SDA_PIN = GPIO24 - SCL_PIN = GPIO25 -) - -// SPI default pins -const ( - // Default Serial Clock Bus 0 for SPI communications - SPI0_SCK_PIN = GPIO6 - // Default Serial Out Bus 0 for SPI communications - SPI0_SDO_PIN = GPIO3 // Tx - // Default Serial In Bus 0 for SPI communications - SPI0_SDI_PIN = GPIO4 // Rx - SPI0_CS = GPIO5 - - // Default Serial Clock Bus 1 for SPI communications - SPI1_SCK_PIN = GPIO26 - // Default Serial Out Bus 1 for SPI communications - SPI1_SDO_PIN = GPIO27 // Tx - // Default Serial In Bus 1 for SPI communications - SPI1_SDI_PIN = GPIO24 // Rx - SPI1_CS = GPIO25 -) - -// UART pins -const ( - UART0_TX_PIN = GPIO28 - UART0_RX_PIN = GPIO29 - UART1_TX_PIN = GPIO20 - UART1_RX_PIN = GPIO5 - UART_TX_PIN = UART0_TX_PIN - UART_RX_PIN = UART0_RX_PIN -) - -var DefaultUART = UART0 - -// USB identifiers -const ( - usb_STRING_PRODUCT = "QT Py RP2040" - usb_STRING_MANUFACTURER = "Adafruit" -) - -var ( - usb_VID uint16 = 0x239A - usb_PID uint16 = 0x80F7 -) diff --git a/emb/machine/board_rak4631.go b/emb/machine/board_rak4631.go deleted file mode 100644 index c59f371..0000000 --- a/emb/machine/board_rak4631.go +++ /dev/null @@ -1,86 +0,0 @@ -//go:build rak4631 - -package machine - -const HasLowFrequencyCrystal = true - -// Digital Pins -const ( - D0 Pin = P0_28 - D1 Pin = P0_02 -) - -// Analog pins -const ( - A0 Pin = P0_17 - A1 Pin = P1_02 - A2 Pin = P0_21 -) - -// Onboard LEDs -const ( - LED = LED2 - LED1 = P1_03 - LED2 = P1_04 -) - -// UART pins -const ( - // Default to UART1 - UART_RX_PIN = UART0_RX_PIN - UART_TX_PIN = UART0_TX_PIN - - // UART1 - UART0_RX_PIN = P0_19 - UART0_TX_PIN = P0_20 - - // UART2 - UART1_RX_PIN = P0_15 - UART1_TX_PIN = P0_16 -) - -// I2C pins -const ( - SDA_PIN = SDA1_PIN - SCL_PIN = SCL1_PIN - - SDA1_PIN = P0_13 - SCL1_PIN = P0_14 - - SDA2_PIN = P0_24 - SCL2_PIN = P0_25 -) - -// SPI pins -const ( - SPI0_SCK_PIN = P0_03 - SPI0_SDO_PIN = P0_29 - SPI0_SDI_PIN = P0_30 -) - -// Peripherals -const ( - LORA_NSS = P1_10 - LORA_SCK = P1_11 - LORA_MOSI = P1_12 - LORA_MISO = P1_13 - LORA_BUSY = P1_14 - LORA_DIO1 = P1_15 - LORA_NRESET = P1_06 - LORA_POWER = P1_05 -) - -// USB CDC identifiers -const ( - usb_STRING_PRODUCT = "WisCore RAK4631 Board" - usb_STRING_MANUFACTURER = "RAKwireless" -) - -var ( - usb_VID uint16 = 0x239a - usb_PID uint16 = 0x8029 -) - -var ( - DefaultUART = UART0 -) diff --git a/emb/machine/board_reelboard.go b/emb/machine/board_reelboard.go deleted file mode 100644 index 3c84070..0000000 --- a/emb/machine/board_reelboard.go +++ /dev/null @@ -1,74 +0,0 @@ -//go:build reelboard - -package machine - -const HasLowFrequencyCrystal = true - -// Pins on the reel board -const ( - LED_RED Pin = 11 - LED_GREEN Pin = 12 - LED_BLUE Pin = 41 - LED_YELLOW Pin = 13 - LED1 Pin = LED_YELLOW - LED2 Pin = LED_RED - LED3 Pin = LED_GREEN - LED4 Pin = LED_BLUE - LED Pin = LED1 - EPD_BUSY_PIN Pin = 14 - EPD_RESET_PIN Pin = 15 - EPD_DC_PIN Pin = 16 - EPD_CS_PIN Pin = 17 - EPD_SCK_PIN Pin = 19 - EPD_SDO_PIN Pin = 20 - POWER_SUPPLY_PIN Pin = 32 -) - -// User "a" button on the reel board -const ( - BUTTON Pin = 7 -) - -var DefaultUART = UART0 - -// UART pins -const ( - UART_TX_PIN Pin = 6 - UART_RX_PIN Pin = 8 -) - -// I2C pins -const ( - SDA_PIN Pin = 26 - SCL_PIN Pin = 27 -) - -// SPI pins -const ( - SPI0_SCK_PIN Pin = 47 - SPI0_SDO_PIN Pin = 45 - SPI0_SDI_PIN Pin = 46 -) - -// PowerSupplyActive enables the supply voltages for nRF52840 and peripherals (true) or only for nRF52840 (false) -// This controls the TPS610981 boost converter. You must turn the power supply active in order to use the EPD and -// other onboard peripherals. -func PowerSupplyActive(active bool) { - POWER_SUPPLY_PIN.Configure(PinConfig{Mode: PinOutput}) - if active { - POWER_SUPPLY_PIN.High() - } else { - POWER_SUPPLY_PIN.Low() - } -} - -// USB CDC identifiers -const ( - usb_STRING_PRODUCT = "PHYTEC reelboard" - usb_STRING_MANUFACTURER = "PHYTEC" -) - -var ( - usb_VID uint16 = 0x2FE3 - usb_PID uint16 = 0x100 -) diff --git a/emb/machine/board_stm32f469disco.go b/emb/machine/board_stm32f469disco.go deleted file mode 100644 index 8fb5cde..0000000 --- a/emb/machine/board_stm32f469disco.go +++ /dev/null @@ -1,79 +0,0 @@ -//go:build stm32f469disco - -package machine - -import ( - "device/stm32" - "runtime/interrupt" -) - -const ( - LED = LED_BUILTIN - LED1 = LED_GREEN - LED2 = LED_ORANGE - LED3 = LED_RED - LED4 = LED_BLUE - LED_BUILTIN = LED_GREEN - LED_GREEN = PG6 - LED_ORANGE = PD4 - LED_RED = PD5 - LED_BLUE = PK3 -) - -const ( - BUTTON = PA0 -) - -// UART pins -const ( - UART_TX_PIN = PB10 - UART_RX_PIN = PB11 -) - -var ( - UART3 = &_UART3 - _UART3 = UART{ - Buffer: NewRingBuffer(), - Bus: stm32.USART3, - TxAltFuncSelector: AF7_USART1_2_3, - RxAltFuncSelector: AF7_USART1_2_3, - } - DefaultUART = UART3 -) - -// set up RX IRQ handler. Follow similar pattern for other UARTx instances -func init() { - UART3.Interrupt = interrupt.New(stm32.IRQ_USART3, _UART3.handleInterrupt) -} - -// SPI pins -const ( - SPI1_SCK_PIN = PA5 - SPI1_SDI_PIN = PA6 - SPI1_SDO_PIN = PA7 - SPI0_SCK_PIN = SPI1_SCK_PIN - SPI0_SDI_PIN = SPI1_SDI_PIN - SPI0_SDO_PIN = SPI1_SDO_PIN -) - -// Since the first interface is named SPI1, both SPI0 and SPI1 refer to SPI1. -// TODO: implement SPI2 and SPI3. -var ( - SPI0 = &SPI{ - Bus: stm32.SPI1, - AltFuncSelector: AF5_SPI1_SPI2, - } - SPI1 = SPI0 -) - -const ( - I2C0_SCL_PIN = PB6 - I2C0_SDA_PIN = PB9 -) - -var ( - I2C0 = &I2C{ - Bus: stm32.I2C1, - AltFuncSelector: AF4_I2C1_2_3, - } -) diff --git a/emb/machine/board_stm32f4disco.go b/emb/machine/board_stm32f4disco.go deleted file mode 100644 index d048fca..0000000 --- a/emb/machine/board_stm32f4disco.go +++ /dev/null @@ -1,106 +0,0 @@ -//go:build stm32f4disco - -package machine - -import ( - "device/stm32" - "runtime/interrupt" -) - -const ( - LED1 = LED_GREEN - LED2 = LED_ORANGE - LED3 = LED_RED - LED4 = LED_BLUE - LED_GREEN = PD12 - LED_ORANGE = PD13 - LED_RED = PD14 - LED_BLUE = PD15 - LED = LED_BUILTIN - LED_BUILTIN = LED_GREEN -) - -const ( - BUTTON = PA0 -) - -// Analog Pins -const ( - ADC0 = PA0 - ADC1 = PA1 - ADC2 = PA2 - ADC3 = PA3 - ADC4 = PA4 - ADC5 = PA5 - ADC6 = PA6 - ADC7 = PA7 - ADC8 = PB0 - ADC9 = PB1 - ADC10 = PC0 - ADC11 = PC1 - ADC12 = PC2 - ADC13 = PC3 - ADC14 = PC4 - ADC15 = PC5 -) - -// UART pins -const ( - UART_TX_PIN = PA2 - UART_RX_PIN = PA3 -) - -var ( - UART1 = &_UART1 - _UART1 = UART{ - Buffer: NewRingBuffer(), - Bus: stm32.USART2, - TxAltFuncSelector: AF7_USART1_2_3, - RxAltFuncSelector: AF7_USART1_2_3, - } - DefaultUART = UART1 -) - -// set up RX IRQ handler. Follow similar pattern for other UARTx instances -func init() { - UART1.Interrupt = interrupt.New(stm32.IRQ_USART2, _UART1.handleInterrupt) -} - -// SPI pins -const ( - SPI1_SCK_PIN = PA5 - SPI1_SDI_PIN = PA6 - SPI1_SDO_PIN = PA7 - SPI0_SCK_PIN = SPI1_SCK_PIN - SPI0_SDI_PIN = SPI1_SDI_PIN - SPI0_SDO_PIN = SPI1_SDO_PIN -) - -// MEMs accelerometer -const ( - MEMS_ACCEL_CS = PE3 - MEMS_ACCEL_INT1 = PE0 - MEMS_ACCEL_INT2 = PE1 -) - -// Since the first interface is named SPI1, both SPI0 and SPI1 refer to SPI1. -// TODO: implement SPI2 and SPI3. -var ( - SPI0 = &SPI{ - Bus: stm32.SPI1, - AltFuncSelector: AF5_SPI1_SPI2, - } - SPI1 = SPI0 -) - -const ( - I2C0_SCL_PIN = PB6 - I2C0_SDA_PIN = PB9 -) - -var ( - I2C0 = &I2C{ - Bus: stm32.I2C1, - AltFuncSelector: AF4_I2C1_2_3, - } -) diff --git a/emb/machine/board_swan.go b/emb/machine/board_swan.go deleted file mode 100644 index 7502dd6..0000000 --- a/emb/machine/board_swan.go +++ /dev/null @@ -1,62 +0,0 @@ -//go:build swan - -package machine - -import ( - "device/stm32" - "runtime/interrupt" -) - -const ( - // LED on the SWAN - LED = PE2 - - // UART pins - // PA9 and PA10 are connected to the SWAN Tx/Rx - UART_TX_PIN = PA9 - UART_RX_PIN = PA10 - - // I2C pins - // PB6 is SCL - // PB7 is SDA - I2C0_SCL_PIN = PB6 - I2C0_SDA_PIN = PB7 - - // SPI pins - SPI1_SCK_PIN = PD1 - SPI1_SDI_PIN = PB14 - SPI1_SDO_PIN = PB15 - SPI0_SCK_PIN = SPI1_SCK_PIN - SPI0_SDI_PIN = SPI1_SDI_PIN - SPI0_SDO_PIN = SPI1_SDO_PIN -) - -var ( - // USART1 is connected to the TX/RX pins - UART1 = &_UART1 - _UART1 = UART{ - Buffer: NewRingBuffer(), - Bus: stm32.USART1, - TxAltFuncSelector: 7, - RxAltFuncSelector: 7, - } - DefaultUART = UART1 - - // I2C1 is documented, alias to I2C0 as well - I2C1 = &I2C{ - Bus: stm32.I2C1, - AltFuncSelector: 4, - } - I2C0 = I2C1 - - // SPI1 is documented, alias to SPI0 as well - SPI1 = &SPI{ - Bus: stm32.SPI2, - AltFuncSelector: 5, - } - SPI0 = SPI1 -) - -func init() { - UART1.Interrupt = interrupt.New(stm32.IRQ_USART1, _UART1.handleInterrupt) -} diff --git a/emb/machine/board_teensy36.go b/emb/machine/board_teensy36.go deleted file mode 100644 index 4859154..0000000 --- a/emb/machine/board_teensy36.go +++ /dev/null @@ -1,103 +0,0 @@ -//go:build nxp && mk66f18 && teensy36 - -package machine - -// CPUFrequency returns the frequency of the ARM core clock (180MHz) -func CPUFrequency() uint32 { return 180000000 } - -// ClockFrequency returns the frequency of the external oscillator (16MHz) -func ClockFrequency() uint32 { return 16000000 } - -// digital IO -const ( - D00 = PB16 - D01 = PB17 - D02 = PD00 - D03 = PA12 - D04 = PA13 - D05 = PD07 - D06 = PD04 - D07 = PD02 - D08 = PD03 - D09 = PC03 - D10 = PC04 - D11 = PC06 - D12 = PC07 - D13 = PC05 - D14 = PD01 - D15 = PC00 - D16 = PB00 - D17 = PB01 - D18 = PB03 - D19 = PB02 - D20 = PD05 - D21 = PD06 - D22 = PC01 - D23 = PC02 - D24 = PE26 - D25 = PA05 - D26 = PA14 - D27 = PA15 - D28 = PA16 - D29 = PB18 - D30 = PB19 - D31 = PB10 - D32 = PB11 - D33 = PE24 - D34 = PE25 - D35 = PC08 - D36 = PC09 - D37 = PC10 - D38 = PC11 - D39 = PA17 - D40 = PA28 - D41 = PA29 - D42 = PA26 - D43 = PB20 - D44 = PB22 - D45 = PB23 - D46 = PB21 - D47 = PD08 - D48 = PD09 - D49 = PB04 - D50 = PB05 - D51 = PD14 - D52 = PD13 - D53 = PD12 - D54 = PD15 - D55 = PD11 - D56 = PE10 - D57 = PE11 - D58 = PE00 - D59 = PE01 - D60 = PE02 - D61 = PE03 - D62 = PE04 - D63 = PE05 -) - -// LED on the Teensy -const LED = PC05 - -var ( - TeensyUART1 = UART0 - TeensyUART2 = UART1 - TeensyUART3 = UART2 - TeensyUART4 = UART3 - TeensyUART5 = UART4 -) - -var DefaultUART = UART0 - -const ( - defaultUART0RX = D00 - defaultUART0TX = D01 - defaultUART1RX = D09 - defaultUART1TX = D10 - defaultUART2RX = D07 - defaultUART2TX = D08 - defaultUART3RX = D31 - defaultUART3TX = D32 - defaultUART4RX = D34 - defaultUART4TX = D33 -) diff --git a/emb/machine/board_teensy40.go b/emb/machine/board_teensy40.go deleted file mode 100644 index 22529a8..0000000 --- a/emb/machine/board_teensy40.go +++ /dev/null @@ -1,390 +0,0 @@ -//go:build teensy40 - -package machine - -import ( - "device/nxp" - "runtime/interrupt" -) - -// Digital pins -const ( - // = Pin // [Pad]: Alt Func 0 Alt Func 1 Alt Func 2 Alt Func 3 Alt Func 4 Alt Func 5 Alt Func 6 Alt Func 7 Alt Func 8 Alt Func 9 - // = ---- ----------- --------------- --------------- --------------- -------------- -------------------- ---------- -------------------- --------------------- --------------------- ---------------- - D0 = PA3 // [AD_B0_03]: FLEXCAN2_RX XBAR1_INOUT17 LPUART6_RX USB_OTG1_OC FLEXPWM1_PWMX01 GPIO1_IO03 REF_CLK_24M LPSPI3_PCS0 ~ ~ - D1 = PA2 // [AD_B0_02]: FLEXCAN2_TX XBAR1_INOUT16 LPUART6_TX USB_OTG1_PWR FLEXPWM1_PWMX00 GPIO1_IO02 LPI2C1_HREQ LPSPI3_SDI ~ ~ - D2 = PD4 // [EMC_04]: SEMC_DATA04 FLEXPWM4_PWMA02 SAI2_TX_DATA XBAR1_INOUT06 FLEXIO1_FLEXIO04 GPIO4_IO04 ~ ~ ~ ~ - D3 = PD5 // [EMC_05]: SEMC_DATA05 FLEXPWM4_PWMB02 SAI2_TX_SYNC XBAR1_INOUT07 FLEXIO1_FLEXIO05 GPIO4_IO05 ~ ~ ~ ~ - D4 = PD6 // [EMC_06]: SEMC_DATA06 FLEXPWM2_PWMA00 SAI2_TX_BCLK XBAR1_INOUT08 FLEXIO1_FLEXIO06 GPIO4_IO06 ~ ~ ~ ~ - D5 = PD8 // [EMC_08]: SEMC_DM00 FLEXPWM2_PWMA01 SAI2_RX_DATA XBAR1_INOUT17 FLEXIO1_FLEXIO08 GPIO4_IO08 ~ ~ ~ ~ - D6 = PB10 // [B0_10]: LCD_DATA06 QTIMER4_TIMER1 FLEXPWM2_PWMA02 SAI1_TX_DATA03 FLEXIO2_FLEXIO10 GPIO2_IO10 SRC_BOOT_CFG06 ENET2_CRS ~ ~ - D7 = PB17 // [B1_01]: LCD_DATA13 XBAR1_INOUT15 LPUART4_RX SAI1_TX_DATA00 FLEXIO2_FLEXIO17 GPIO2_IO17 FLEXPWM1_PWMB03 ENET2_RDATA00 FLEXIO3_FLEXIO17 ~ - D8 = PB16 // [B1_00]: LCD_DATA12 XBAR1_INOUT14 LPUART4_TX SAI1_RX_DATA00 FLEXIO2_FLEXIO16 GPIO2_IO16 FLEXPWM1_PWMA03 ENET2_RX_ER FLEXIO3_FLEXIO16 ~ - D9 = PB11 // [B0_11]: LCD_DATA07 QTIMER4_TIMER2 FLEXPWM2_PWMB02 SAI1_TX_DATA02 FLEXIO2_FLEXIO11 GPIO2_IO11 SRC_BOOT_CFG07 ENET2_COL ~ ~ - D10 = PB0 // [B0_00]: LCD_CLK QTIMER1_TIMER0 MQS_RIGHT LPSPI4_PCS0 FLEXIO2_FLEXIO00 GPIO2_IO00 SEMC_CSX01 ENET2_MDC ~ ~ - D11 = PB2 // [B0_02]: LCD_HSYNC QTIMER1_TIMER2 FLEXCAN1_TX LPSPI4_SDO FLEXIO2_FLEXIO02 GPIO2_IO02 SEMC_CSX03 ENET2_1588_EVENT0_OUT ~ ~ - D12 = PB1 // [B0_01]: LCD_ENABLE QTIMER1_TIMER1 MQS_LEFT LPSPI4_SDI FLEXIO2_FLEXIO01 GPIO2_IO01 SEMC_CSX02 ENET2_MDIO ~ ~ - D13 = PB3 // [B0_03]: LCD_VSYNC QTIMER2_TIMER0 FLEXCAN1_RX LPSPI4_SCK FLEXIO2_FLEXIO03 GPIO2_IO03 WDOG2_RESET_B_DEB ENET2_1588_EVENT0_IN ~ ~ - D14 = PA18 // [AD_B1_02]: USB_OTG1_ID QTIMER3_TIMER2 LPUART2_TX SPDIF_OUT ENET_1588_EVENT2_OUT GPIO1_IO18 USDHC1_CD_B KPP_ROW06 GPT2_CLK FLEXIO3_FLEXIO02 - D15 = PA19 // [AD_B1_03]: USB_OTG1_OC QTIMER3_TIMER3 LPUART2_RX SPDIF_IN ENET_1588_EVENT2_IN GPIO1_IO19 USDHC2_CD_B KPP_COL06 GPT2_CAPTURE1 FLEXIO3_FLEXIO03 - D16 = PA23 // [AD_B1_07]: FLEXSPIB_DATA00 LPI2C3_SCL LPUART3_RX SPDIF_EXT_CLK CSI_HSYNC GPIO1_IO23 USDHC2_DATA3 KPP_COL04 GPT2_COMPARE3 FLEXIO3_FLEXIO07 - D17 = PA22 // [AD_B1_06]: FLEXSPIB_DATA01 LPI2C3_SDA LPUART3_TX SPDIF_LOCK CSI_VSYNC GPIO1_IO22 USDHC2_DATA2 KPP_ROW04 GPT2_COMPARE2 FLEXIO3_FLEXIO06 - D18 = PA17 // [AD_B1_01]: USB_OTG1_PWR QTIMER3_TIMER1 LPUART2_RTS_B LPI2C1_SDA CCM_PMIC_READY GPIO1_IO17 USDHC1_VSELECT KPP_COL07 ENET2_1588_EVENT0_IN FLEXIO3_FLEXIO01 - D19 = PA16 // [AD_B1_00]: USB_OTG2_ID QTIMER3_TIMER0 LPUART2_CTS_B LPI2C1_SCL WDOG1_B GPIO1_IO16 USDHC1_WP KPP_ROW07 ENET2_1588_EVENT0_OUT FLEXIO3_FLEXIO00 - D20 = PA26 // [AD_B1_10]: FLEXSPIA_DATA03 WDOG1_B LPUART8_TX SAI1_RX_SYNC CSI_DATA07 GPIO1_IO26 USDHC2_WP KPP_ROW02 ENET2_1588_EVENT1_OUT FLEXIO3_FLEXIO10 - D21 = PA27 // [AD_B1_11]: FLEXSPIA_DATA02 EWM_OUT_B LPUART8_RX SAI1_RX_BCLK CSI_DATA06 GPIO1_IO27 USDHC2_RESET_B KPP_COL02 ENET2_1588_EVENT1_IN FLEXIO3_FLEXIO11 - D22 = PA24 // [AD_B1_08]: FLEXSPIA_SS1_B FLEXPWM4_PWMA00 FLEXCAN1_TX CCM_PMIC_READY CSI_DATA09 GPIO1_IO24 USDHC2_CMD KPP_ROW03 FLEXIO3_FLEXIO08 ~ - D23 = PA25 // [AD_B1_09]: FLEXSPIA_DQS FLEXPWM4_PWMA01 FLEXCAN1_RX SAI1_MCLK CSI_DATA08 GPIO1_IO25 USDHC2_CLK KPP_COL03 FLEXIO3_FLEXIO09 ~ - D24 = PA12 // [AD_B0_12]: LPI2C4_SCL CCM_PMIC_READY LPUART1_TX WDOG2_WDOG_B FLEXPWM1_PWMX02 GPIO1_IO12 ENET_1588_EVENT1_OUT NMI_GLUE_NMI ~ ~ - D25 = PA13 // [AD_B0_13]: LPI2C4_SDA GPT1_CLK LPUART1_RX EWM_OUT_B FLEXPWM1_PWMX03 GPIO1_IO13 ENET_1588_EVENT1_IN REF_CLK_24M ~ ~ - D26 = PA30 // [AD_B1_14]: FLEXSPIA_SCLK ACMP_OUT02 LPSPI3_SDO SAI1_TX_BCLK CSI_DATA03 GPIO1_IO30 USDHC2_DATA6 KPP_ROW00 ENET2_1588_EVENT3_OUT FLEXIO3_FLEXIO14 - D27 = PA31 // [AD_B1_15]: FLEXSPIA_SS0_B ACMP_OUT03 LPSPI3_SCK SAI1_TX_SYNC CSI_DATA02 GPIO1_IO31 USDHC2_DATA7 KPP_COL00 ENET2_1588_EVENT3_IN FLEXIO3_FLEXIO15 - D28 = PC18 // [EMC_32]: SEMC_DATA10 FLEXPWM3_PWMB01 LPUART7_RX CCM_PMIC_RDY CSI_DATA21 GPIO3_IO18 ENET2_TX_EN ~ ~ ~ - D29 = PD31 // [EMC_31]: SEMC_DATA09 FLEXPWM3_PWMA01 LPUART7_TX LPSPI1_PCS1 CSI_DATA22 GPIO4_IO31 ENET2_TDATA01 ~ ~ ~ - D30 = PC23 // [EMC_37]: SEMC_DATA15 XBAR1_IN23 GPT1_COMPARE3 SAI3_MCLK CSI_DATA16 GPIO3_IO23 USDHC2_WP ENET2_RX_EN FLEXCAN3_RX ~ - D31 = PC22 // [EMC_36]: SEMC_DATA14 XBAR1_IN22 GPT1_COMPARE2 SAI3_TX_DATA CSI_DATA17 GPIO3_IO22 USDHC1_WP ENET2_RDATA01 FLEXCAN3_TX ~ - D32 = PB12 // [B0_12]: LCD_DATA08 XBAR1_INOUT10 ARM_TRACE_CLK SAI1_TX_DATA01 FLEXIO2_FLEXIO12 GPIO2_IO12 SRC_BOOT_CFG08 ENET2_TDATA00 ~ ~ - D33 = PD7 // [EMC_07]: SEMC_DATA07 FLEXPWM2_PWMB00 SAI2_MCLK XBAR1_INOUT09 FLEXIO1_FLEXIO07 GPIO4_IO07 ~ ~ ~ ~ - D34 = PC15 // [SD_B0_03]: USDHC1_DATA1 FLEXPWM1_PWMB01 LPUART8_RTS_B XBAR1_INOUT07 LPSPI1_SDI GPIO3_IO15 ENET2_RDATA00 SEMC_CLK6 ~ ~ - D35 = PC14 // [SD_B0_02]: USDHC1_DATA0 FLEXPWM1_PWMA01 LPUART8_CTS_B XBAR1_INOUT06 LPSPI1_SDO GPIO3_IO14 ENET2_RX_ER SEMC_CLK5 ~ ~ - D36 = PC13 // [SD_B0_01]: USDHC1_CLK FLEXPWM1_PWMB00 LPI2C3_SDA XBAR1_INOUT05 LPSPI1_PCS0 GPIO3_IO13 FLEXSPIB_SS1_B ENET2_TX_CLK ENET2_REF_CLK2 ~ - D37 = PC12 // [SD_B0_00]: USDHC1_CMD FLEXPWM1_PWMA00 LPI2C3_SCL XBAR1_INOUT04 LPSPI1_SCK GPIO3_IO12 FLEXSPIA_SS1_B ENET2_TX_EN SEMC_DQS4 ~ - D38 = PC17 // [SD_B0_05]: USDHC1_DATA3 FLEXPWM1_PWMB02 LPUART8_RX XBAR1_INOUT09 FLEXSPIB_DQS GPIO3_IO17 CCM_CLKO2 ENET2_RX_EN ~ ~ - D39 = PC16 // [SD_B0_04]: USDHC1_DATA2 FLEXPWM1_PWMA02 LPUART8_TX XBAR1_INOUT08 FLEXSPIB_SS0_B GPIO3_IO16 CCM_CLKO1 ENET2_RDATA01 ~ ~ -) - -// Analog pins -const ( - // = Pin // Dig | [Pad] {ADC1/ADC2} - A0 = PA18 // D14 | [AD_B1_02] { 7 / 7 } - A1 = PA19 // D15 | [AD_B1_03] { 8 / 8 } - A2 = PA23 // D16 | [AD_B1_07] { 12 / 12 } - A3 = PA22 // D17 | [AD_B1_06] { 11 / 11 } - A4 = PA17 // D18 | [AD_B1_01] { 6 / 6 } - A5 = PA16 // D19 | [AD_B1_00] { 5 / 5 } - A6 = PA26 // D20 | [AD_B1_10] { 15 / 15 } - A7 = PA27 // D21 | [AD_B1_11] { 0 / 0 } - A8 = PA24 // D22 | [AD_B1_08] { 13 / 13 } - A9 = PA25 // D23 | [AD_B1_09] { 14 / 14 } - A10 = PA12 // D24 | [AD_B0_12] { 1 / - } - A11 = PA13 // D25 | [AD_B0_13] { 2 / - } - A12 = PA30 // D26 | [AD_B1_14] { - / 3 } - A13 = PA31 // D27 | [AD_B1_15] { - / 4 } -) - -// Default peripheral pins -const ( - LED = D13 - - UART_RX_PIN = UART1_RX_PIN // D0 - UART_TX_PIN = UART1_TX_PIN // D1 - - SPI_SDI_PIN = SPI1_SDI_PIN // D12 - SPI_SDO_PIN = SPI1_SDO_PIN // D11 - SPI_SCK_PIN = SPI1_SCK_PIN // D13 - SPI_CS_PIN = SPI1_CS_PIN // D10 - - I2C_SDA_PIN = I2C1_SDA_PIN // D18/A4 - I2C_SCL_PIN = I2C1_SCL_PIN // D19/A5 -) - -// Default peripherals -var ( - DefaultUART = UART1 -) - -func init() { - // register any interrupt handlers for this board's peripherals - _UART1.Interrupt = interrupt.New(nxp.IRQ_LPUART6, _UART1.handleInterrupt) - _UART2.Interrupt = interrupt.New(nxp.IRQ_LPUART4, _UART2.handleInterrupt) - _UART3.Interrupt = interrupt.New(nxp.IRQ_LPUART2, _UART3.handleInterrupt) - _UART4.Interrupt = interrupt.New(nxp.IRQ_LPUART3, _UART4.handleInterrupt) - _UART5.Interrupt = interrupt.New(nxp.IRQ_LPUART8, _UART5.handleInterrupt) - _UART6.Interrupt = interrupt.New(nxp.IRQ_LPUART1, _UART6.handleInterrupt) - _UART7.Interrupt = interrupt.New(nxp.IRQ_LPUART7, _UART7.handleInterrupt) -} - -// #=====================================================# -// | UART | -// #===========#===========#=============#===============# -// | Interface | Hardware | Clock(Freq) | RX/TX : Alt | -// #===========#===========#=============#=========-=====# -// | UART1 | LPUART6 | OSC(24 MHz) | D0/D1 : 2/2 | -// | UART2 | LPUART4 | OSC(24 MHz) | D7/D8 : 2/2 | -// | UART3 | LPUART2 | OSC(24 MHz) | D15/D14 : 2/2 | -// | UART4 | LPUART3 | OSC(24 MHz) | D16/D17 : 2/2 | -// | UART5 | LPUART8 | OSC(24 MHz) | D21/D20 : 2/2 | -// | UART6 | LPUART1 | OSC(24 MHz) | D25/D24 : 2/2 | -// | UART7 | LPUART7 | OSC(24 MHz) | D28/D29 : 2/2 | -// #===========#===========#=============#=========-=====# -const ( - UART1_RX_PIN = D0 - UART1_TX_PIN = D1 - - UART2_RX_PIN = D7 - UART2_TX_PIN = D8 - - UART3_RX_PIN = D15 - UART3_TX_PIN = D14 - - UART4_RX_PIN = D16 - UART4_TX_PIN = D17 - - UART5_RX_PIN = D21 - UART5_TX_PIN = D20 - - UART6_RX_PIN = D25 - UART6_TX_PIN = D24 - - UART7_RX_PIN = D28 - UART7_TX_PIN = D29 -) - -var ( - UART1 = &_UART1 - _UART1 = UART{ - Bus: nxp.LPUART6, - Buffer: NewRingBuffer(), - txBuffer: NewRingBuffer(), - muxRX: muxSelect{ // D0 (PA3 [AD_B0_03]) - mux: nxp.IOMUXC_LPUART6_RX_SELECT_INPUT_DAISY_GPIO_AD_B0_03_ALT2, - sel: &nxp.IOMUXC.LPUART6_RX_SELECT_INPUT, - }, - muxTX: muxSelect{ // D1 (PA2 [AD_B0_02]) - mux: nxp.IOMUXC_LPUART6_TX_SELECT_INPUT_DAISY_GPIO_AD_B0_02_ALT2, - sel: &nxp.IOMUXC.LPUART6_TX_SELECT_INPUT, - }, - } - UART2 = &_UART2 - _UART2 = UART{ - Bus: nxp.LPUART4, - Buffer: NewRingBuffer(), - txBuffer: NewRingBuffer(), - muxRX: muxSelect{ // D7 (PB17 [B1_01]) - mux: nxp.IOMUXC_LPUART4_RX_SELECT_INPUT_DAISY_GPIO_B1_01_ALT2, - sel: &nxp.IOMUXC.LPUART4_RX_SELECT_INPUT, - }, - muxTX: muxSelect{ // D8 (PB16 [B1_00]) - mux: nxp.IOMUXC_LPUART4_TX_SELECT_INPUT_DAISY_GPIO_B1_00_ALT2, - sel: &nxp.IOMUXC.LPUART4_TX_SELECT_INPUT, - }, - } - UART3 = &_UART3 - _UART3 = UART{ - Bus: nxp.LPUART2, - Buffer: NewRingBuffer(), - txBuffer: NewRingBuffer(), - muxRX: muxSelect{ // D15 (PA19 [AD_B1_03]) - mux: nxp.IOMUXC_LPUART2_RX_SELECT_INPUT_DAISY_GPIO_AD_B1_03_ALT2, - sel: &nxp.IOMUXC.LPUART2_RX_SELECT_INPUT, - }, - muxTX: muxSelect{ // D14 (PA18 [AD_B1_02]) - mux: nxp.IOMUXC_LPUART2_TX_SELECT_INPUT_DAISY_GPIO_AD_B1_02_ALT2, - sel: &nxp.IOMUXC.LPUART2_TX_SELECT_INPUT, - }, - } - UART4 = &_UART4 - _UART4 = UART{ - Bus: nxp.LPUART3, - Buffer: NewRingBuffer(), - txBuffer: NewRingBuffer(), - muxRX: muxSelect{ // D16 (PA23 [AD_B1_07]) - mux: nxp.IOMUXC_LPUART3_RX_SELECT_INPUT_DAISY_GPIO_AD_B1_07_ALT2, - sel: &nxp.IOMUXC.LPUART3_RX_SELECT_INPUT, - }, - muxTX: muxSelect{ // D17 (PA22 [AD_B1_06]) - mux: nxp.IOMUXC_LPUART3_TX_SELECT_INPUT_DAISY_GPIO_AD_B1_06_ALT2, - sel: &nxp.IOMUXC.LPUART3_TX_SELECT_INPUT, - }, - } - UART5 = &_UART5 - _UART5 = UART{ - Bus: nxp.LPUART8, - Buffer: NewRingBuffer(), - txBuffer: NewRingBuffer(), - muxRX: muxSelect{ // D21 (PA27 [AD_B1_11]) - mux: nxp.IOMUXC_LPUART8_RX_SELECT_INPUT_DAISY_GPIO_AD_B1_11_ALT2, - sel: &nxp.IOMUXC.LPUART8_RX_SELECT_INPUT, - }, - muxTX: muxSelect{ // D20 (PA26 [AD_B1_10]) - mux: nxp.IOMUXC_LPUART8_TX_SELECT_INPUT_DAISY_GPIO_AD_B1_10_ALT2, - sel: &nxp.IOMUXC.LPUART8_TX_SELECT_INPUT, - }, - } - UART6 = &_UART6 - _UART6 = UART{ - Bus: nxp.LPUART1, - Buffer: NewRingBuffer(), - txBuffer: NewRingBuffer(), - // LPUART1 not connected via IOMUXC - // RX: D24 (PA12 [AD_B0_12]) - // TX: D25 (PA13 [AD_B0_13]) - } - UART7 = &_UART7 - _UART7 = UART{ - Bus: nxp.LPUART7, - Buffer: NewRingBuffer(), - txBuffer: NewRingBuffer(), - muxRX: muxSelect{ // D28 (PC18 [EMC_32]) - mux: nxp.IOMUXC_LPUART7_RX_SELECT_INPUT_DAISY_GPIO_EMC_32_ALT2, - sel: &nxp.IOMUXC.LPUART7_RX_SELECT_INPUT, - }, - muxTX: muxSelect{ // D29 (PD31 [EMC_31]) - mux: nxp.IOMUXC_LPUART7_TX_SELECT_INPUT_DAISY_GPIO_EMC_31_ALT2, - sel: &nxp.IOMUXC.LPUART7_TX_SELECT_INPUT, - }, - } -) - -// #==================================================================# -// | SPI | -// #===========#==========#===============#===========================# -// | Interface | Hardware | Clock(Freq) | SDI/SDO/SCK/CS : Alt | -// #===========#==========#===============#=================-=========# -// | SPI1 | LPSPI4 | PLL2(132 MHz) | D12/D11/D13/D10 : 3/3/3/3 | -// | SPI2 | LPSPI3 | PLL2(132 MHz) | D1/D26/D27/D0 : 7/2/2/7 | -// | SPI3 | LPSPI1 | PLL2(132 MHz) | D34/D35/D37/D36 : 4/4/4/4 | -// #===========#==========#===============#=================-=========# -const ( - SPI1_SDI_PIN = D12 - SPI1_SDO_PIN = D11 - SPI1_SCK_PIN = D13 - SPI1_CS_PIN = D10 - - SPI2_SDI_PIN = D1 - SPI2_SDO_PIN = D26 - SPI2_SCK_PIN = D27 - SPI2_CS_PIN = D0 - - SPI3_SDI_PIN = D34 - SPI3_SDO_PIN = D35 - SPI3_SCK_PIN = D37 - SPI3_CS_PIN = D36 -) - -var ( - SPI0 = SPI1 // SPI0 is an alias of SPI1 (LPSPI4) - SPI1 = &SPI{ - Bus: nxp.LPSPI4, - muxSDI: muxSelect{ // D12 (PB1 [B0_01]) - mux: nxp.IOMUXC_LPSPI4_SDI_SELECT_INPUT_DAISY_GPIO_B0_01_ALT3, - sel: &nxp.IOMUXC.LPSPI4_SDI_SELECT_INPUT, - }, - muxSDO: muxSelect{ // D11 (PB2 [B0_02]) - mux: nxp.IOMUXC_LPSPI4_SDO_SELECT_INPUT_DAISY_GPIO_B0_02_ALT3, - sel: &nxp.IOMUXC.LPSPI4_SDO_SELECT_INPUT, - }, - muxSCK: muxSelect{ // D13 (PB3 [B0_03]) - mux: nxp.IOMUXC_LPSPI4_SCK_SELECT_INPUT_DAISY_GPIO_B0_03_ALT3, - sel: &nxp.IOMUXC.LPSPI4_SCK_SELECT_INPUT, - }, - muxCS: muxSelect{ // D10 (PB0 [B0_00]) - mux: nxp.IOMUXC_LPSPI4_PCS0_SELECT_INPUT_DAISY_GPIO_B0_00_ALT3, - sel: &nxp.IOMUXC.LPSPI4_PCS0_SELECT_INPUT, - }, - } - SPI2 = &SPI{ - Bus: nxp.LPSPI3, - muxSDI: muxSelect{ // D1 (PA2 [AD_B0_02]) - mux: nxp.IOMUXC_LPSPI3_SDI_SELECT_INPUT_DAISY_GPIO_AD_B0_02_ALT7, - sel: &nxp.IOMUXC.LPSPI3_SDI_SELECT_INPUT, - }, - muxSDO: muxSelect{ // D26 (PA30 [AD_B1_14]) - mux: nxp.IOMUXC_LPSPI3_SDO_SELECT_INPUT_DAISY_GPIO_AD_B1_14_ALT2, - sel: &nxp.IOMUXC.LPSPI3_SDO_SELECT_INPUT, - }, - muxSCK: muxSelect{ // D27 (PA31 [AD_B1_15]) - mux: nxp.IOMUXC_LPSPI3_SCK_SELECT_INPUT_DAISY_GPIO_AD_B1_15, - sel: &nxp.IOMUXC.LPSPI3_SCK_SELECT_INPUT, - }, - muxCS: muxSelect{ // D0 (PA3 [AD_B0_03]) - mux: nxp.IOMUXC_LPSPI3_PCS0_SELECT_INPUT_DAISY_GPIO_AD_B0_03_ALT7, - sel: &nxp.IOMUXC.LPSPI3_PCS0_SELECT_INPUT, - }, - } - SPI3 = &SPI{ - Bus: nxp.LPSPI1, - muxSDI: muxSelect{ // D34 (PC15 [SD_B0_03]) - mux: nxp.IOMUXC_LPSPI1_SDI_SELECT_INPUT_DAISY_GPIO_SD_B0_03_ALT4, - sel: &nxp.IOMUXC.LPSPI1_SDI_SELECT_INPUT, - }, - muxSDO: muxSelect{ // D35 (PC14 [SD_B0_02]) - mux: nxp.IOMUXC_LPSPI1_SDO_SELECT_INPUT_DAISY_GPIO_SD_B0_02_ALT4, - sel: &nxp.IOMUXC.LPSPI1_SDO_SELECT_INPUT, - }, - muxSCK: muxSelect{ // D37 (PC12 [SD_B0_00]) - mux: nxp.IOMUXC_LPSPI1_SCK_SELECT_INPUT_DAISY_GPIO_SD_B0_00_ALT4, - sel: &nxp.IOMUXC.LPSPI1_SCK_SELECT_INPUT, - }, - muxCS: muxSelect{ // D36 (PC13 [SD_B0_01]) - mux: nxp.IOMUXC_LPSPI1_PCS0_SELECT_INPUT_DAISY_GPIO_SD_B0_01_ALT4, - sel: &nxp.IOMUXC.LPSPI1_PCS0_SELECT_INPUT, - }, - } -) - -// #====================================================# -// | I2C | -// #===========#==========#=============#===============# -// | Interface | Hardware | Clock(Freq) | SDA/SCL : Alt | -// #===========#==========#=============#=========-=====# -// | I2C1 | LPI2C1 | OSC(24 MHz) | D18/D19 : 3/3 | -// | I2C2 | LPI2C3 | OSC(24 MHz) | D17/D16 : 1/1 | -// | I2C3 | LPI2C4 | OSC(24 MHz) | D25/D24 : 0/0 | -// #===========#==========#=============#=========-=====# -const ( - I2C1_SDA_PIN = D18 - I2C1_SCL_PIN = D19 - - I2C2_SDA_PIN = D17 - I2C2_SCL_PIN = D16 - - I2C3_SDA_PIN = D25 - I2C3_SCL_PIN = D24 -) - -var ( - I2C0 = I2C1 // I2C0 is an alias for I2C1 (LPI2C1) - I2C1 = &_I2C1 - _I2C1 = I2C{ - Bus: nxp.LPI2C1, - sda: I2C1_SDA_PIN, // D18 (PA17 [AD_B1_01]) - scl: I2C1_SCL_PIN, // D19 (PA16 [AD_B1_00]) - muxSDA: muxSelect{ - mux: nxp.IOMUXC_LPI2C1_SDA_SELECT_INPUT_DAISY_GPIO_AD_B1_01_ALT3, - sel: &nxp.IOMUXC.LPI2C1_SDA_SELECT_INPUT, - }, - muxSCL: muxSelect{ - mux: nxp.IOMUXC_LPI2C1_SCL_SELECT_INPUT_DAISY_GPIO_AD_B1_00_ALT3, - sel: &nxp.IOMUXC.LPI2C1_SCL_SELECT_INPUT, - }, - } - I2C2 = &_I2C2 - _I2C2 = I2C{ - Bus: nxp.LPI2C3, - sda: I2C2_SDA_PIN, // D17 (PA22 [AD_B1_06]) - scl: I2C2_SCL_PIN, // D16 (PA23 [AD_B1_07]) - muxSDA: muxSelect{ - mux: nxp.IOMUXC_LPI2C3_SDA_SELECT_INPUT_DAISY_GPIO_AD_B1_06_ALT1, - sel: &nxp.IOMUXC.LPI2C3_SDA_SELECT_INPUT, - }, - muxSCL: muxSelect{ - mux: nxp.IOMUXC_LPI2C3_SCL_SELECT_INPUT_DAISY_GPIO_AD_B1_07_ALT1, - sel: &nxp.IOMUXC.LPI2C3_SCL_SELECT_INPUT, - }, - } - I2C3 = &_I2C3 - _I2C3 = I2C{ - Bus: nxp.LPI2C4, - sda: I2C3_SDA_PIN, // D25 (PA13 [AD_B0_13]) - scl: I2C3_SCL_PIN, // D24 (PA12 [AD_B0_12]) - muxSDA: muxSelect{ - mux: nxp.IOMUXC_LPI2C4_SDA_SELECT_INPUT_DAISY_GPIO_AD_B0_13_ALT0, - sel: &nxp.IOMUXC.LPI2C4_SDA_SELECT_INPUT, - }, - muxSCL: muxSelect{ - mux: nxp.IOMUXC_LPI2C4_SCL_SELECT_INPUT_DAISY_GPIO_AD_B0_12_ALT0, - sel: &nxp.IOMUXC.LPI2C4_SCL_SELECT_INPUT, - }, - } -) diff --git a/emb/machine/board_teensy41.go b/emb/machine/board_teensy41.go deleted file mode 100644 index 436c1b9..0000000 --- a/emb/machine/board_teensy41.go +++ /dev/null @@ -1,319 +0,0 @@ -//go:build teensy41 - -package machine - -import ( - "device/nxp" - "runtime/interrupt" -) - -// Digital pins -const ( - // = Pin // [Pad]: Alt Func 0 Alt Func 1 Alt Func 2 Alt Func 3 Alt Func 4 Alt Func 5 Alt Func 6 Alt Func 7 Alt Func 8 Alt Func 9 - // = ---- ----------- --------------- --------------- --------------- -------------- -------------------- ---------- -------------------- --------------------- --------------------- ---------------- - D0 = PA3 // [AD_B0_03]: FLEXCAN2_RX XBAR1_INOUT17 LPUART6_RX USB_OTG1_OC FLEXPWM1_PWMX01 GPIO1_IO03 REF_CLK_24M LPSPI3_PCS0 ~ ~ - D1 = PA2 // [AD_B0_02]: FLEXCAN2_TX XBAR1_INOUT16 LPUART6_TX USB_OTG1_PWR FLEXPWM1_PWMX00 GPIO1_IO02 LPI2C1_HREQ LPSPI3_SDI ~ ~ - D2 = PD4 // [EMC_04]: SEMC_DATA04 FLEXPWM4_PWMA02 SAI2_TX_DATA XBAR1_INOUT06 FLEXIO1_FLEXIO04 GPIO4_IO04 ~ ~ ~ ~ - D3 = PD5 // [EMC_05]: SEMC_DATA05 FLEXPWM4_PWMB02 SAI2_TX_SYNC XBAR1_INOUT07 FLEXIO1_FLEXIO05 GPIO4_IO05 ~ ~ ~ ~ - D4 = PD6 // [EMC_06]: SEMC_DATA06 FLEXPWM2_PWMA00 SAI2_TX_BCLK XBAR1_INOUT08 FLEXIO1_FLEXIO06 GPIO4_IO06 ~ ~ ~ ~ - D5 = PD8 // [EMC_08]: SEMC_DM00 FLEXPWM2_PWMA01 SAI2_RX_DATA XBAR1_INOUT17 FLEXIO1_FLEXIO08 GPIO4_IO08 ~ ~ ~ ~ - D6 = PB10 // [B0_10]: LCD_DATA06 QTIMER4_TIMER1 FLEXPWM2_PWMA02 SAI1_TX_DATA03 FLEXIO2_FLEXIO10 GPIO2_IO10 SRC_BOOT_CFG06 ENET2_CRS ~ ~ - D7 = PB17 // [B1_01]: LCD_DATA13 XBAR1_INOUT15 LPUART4_RX SAI1_TX_DATA00 FLEXIO2_FLEXIO17 GPIO2_IO17 FLEXPWM1_PWMB03 ENET2_RDATA00 FLEXIO3_FLEXIO17 ~ - D8 = PB16 // [B1_00]: LCD_DATA12 XBAR1_INOUT14 LPUART4_TX SAI1_RX_DATA00 FLEXIO2_FLEXIO16 GPIO2_IO16 FLEXPWM1_PWMA03 ENET2_RX_ER FLEXIO3_FLEXIO16 ~ - D9 = PB11 // [B0_11]: LCD_DATA07 QTIMER4_TIMER2 FLEXPWM2_PWMB02 SAI1_TX_DATA02 FLEXIO2_FLEXIO11 GPIO2_IO11 SRC_BOOT_CFG07 ENET2_COL ~ ~ - D10 = PB0 // [B0_00]: LCD_CLK QTIMER1_TIMER0 MQS_RIGHT LPSPI4_PCS0 FLEXIO2_FLEXIO00 GPIO2_IO00 SEMC_CSX01 ENET2_MDC ~ ~ - D11 = PB2 // [B0_02]: LCD_HSYNC QTIMER1_TIMER2 FLEXCAN1_TX LPSPI4_SDO FLEXIO2_FLEXIO02 GPIO2_IO02 SEMC_CSX03 ENET2_1588_EVENT0_OUT ~ ~ - D12 = PB1 // [B0_01]: LCD_ENABLE QTIMER1_TIMER1 MQS_LEFT LPSPI4_SDI FLEXIO2_FLEXIO01 GPIO2_IO01 SEMC_CSX02 ENET2_MDIO ~ ~ - D13 = PB3 // [B0_03]: LCD_VSYNC QTIMER2_TIMER0 FLEXCAN1_RX LPSPI4_SCK FLEXIO2_FLEXIO03 GPIO2_IO03 WDOG2_RESET_B_DEB ENET2_1588_EVENT0_IN ~ ~ - D14 = PA18 // [AD_B1_02]: USB_OTG1_ID QTIMER3_TIMER2 LPUART2_TX SPDIF_OUT ENET_1588_EVENT2_OUT GPIO1_IO18 USDHC1_CD_B KPP_ROW06 GPT2_CLK FLEXIO3_FLEXIO02 - D15 = PA19 // [AD_B1_03]: USB_OTG1_OC QTIMER3_TIMER3 LPUART2_RX SPDIF_IN ENET_1588_EVENT2_IN GPIO1_IO19 USDHC2_CD_B KPP_COL06 GPT2_CAPTURE1 FLEXIO3_FLEXIO03 - D16 = PA23 // [AD_B1_07]: FLEXSPIB_DATA00 LPI2C3_SCL LPUART3_RX SPDIF_EXT_CLK CSI_HSYNC GPIO1_IO23 USDHC2_DATA3 KPP_COL04 GPT2_COMPARE3 FLEXIO3_FLEXIO07 - D17 = PA22 // [AD_B1_06]: FLEXSPIB_DATA01 LPI2C3_SDA LPUART3_TX SPDIF_LOCK CSI_VSYNC GPIO1_IO22 USDHC2_DATA2 KPP_ROW04 GPT2_COMPARE2 FLEXIO3_FLEXIO06 - D18 = PA17 // [AD_B1_01]: USB_OTG1_PWR QTIMER3_TIMER1 LPUART2_RTS_B LPI2C1_SDA CCM_PMIC_READY GPIO1_IO17 USDHC1_VSELECT KPP_COL07 ENET2_1588_EVENT0_IN FLEXIO3_FLEXIO01 - D19 = PA16 // [AD_B1_00]: USB_OTG2_ID QTIMER3_TIMER0 LPUART2_CTS_B LPI2C1_SCL WDOG1_B GPIO1_IO16 USDHC1_WP KPP_ROW07 ENET2_1588_EVENT0_OUT FLEXIO3_FLEXIO00 - D20 = PA26 // [AD_B1_10]: FLEXSPIA_DATA03 WDOG1_B LPUART8_TX SAI1_RX_SYNC CSI_DATA07 GPIO1_IO26 USDHC2_WP KPP_ROW02 ENET2_1588_EVENT1_OUT FLEXIO3_FLEXIO10 - D21 = PA27 // [AD_B1_11]: FLEXSPIA_DATA02 EWM_OUT_B LPUART8_RX SAI1_RX_BCLK CSI_DATA06 GPIO1_IO27 USDHC2_RESET_B KPP_COL02 ENET2_1588_EVENT1_IN FLEXIO3_FLEXIO11 - D22 = PA24 // [AD_B1_08]: FLEXSPIA_SS1_B FLEXPWM4_PWMA00 FLEXCAN1_TX CCM_PMIC_READY CSI_DATA09 GPIO1_IO24 USDHC2_CMD KPP_ROW03 FLEXIO3_FLEXIO08 ~ - D23 = PA25 // [AD_B1_09]: FLEXSPIA_DQS FLEXPWM4_PWMA01 FLEXCAN1_RX SAI1_MCLK CSI_DATA08 GPIO1_IO25 USDHC2_CLK KPP_COL03 FLEXIO3_FLEXIO09 ~ - D24 = PA12 // [AD_B0_12]: LPI2C4_SCL CCM_PMIC_READY LPUART1_TX WDOG2_WDOG_B FLEXPWM1_PWMX02 GPIO1_IO12 ENET_1588_EVENT1_OUT NMI_GLUE_NMI ~ ~ - D25 = PA13 // [AD_B0_13]: LPI2C4_SDA GPT1_CLK LPUART1_RX EWM_OUT_B FLEXPWM1_PWMX03 GPIO1_IO13 ENET_1588_EVENT1_IN REF_CLK_24M ~ ~ - D26 = PA30 // [AD_B1_14]: FLEXSPIA_SCLK ACMP_OUT02 LPSPI3_SDO SAI1_TX_BCLK CSI_DATA03 GPIO1_IO30 USDHC2_DATA6 KPP_ROW00 ENET2_1588_EVENT3_OUT FLEXIO3_FLEXIO14 - D27 = PA31 // [AD_B1_15]: FLEXSPIA_SS0_B ACMP_OUT03 LPSPI3_SCK SAI1_TX_SYNC CSI_DATA02 GPIO1_IO31 USDHC2_DATA7 KPP_COL00 ENET2_1588_EVENT3_IN FLEXIO3_FLEXIO15 - D28 = PC18 // [EMC_32]: SEMC_DATA10 FLEXPWM3_PWMB01 LPUART7_RX CCM_PMIC_RDY CSI_DATA21 GPIO3_IO18 ENET2_TX_EN ~ ~ ~ - D29 = PD31 // [EMC_31]: SEMC_DATA09 FLEXPWM3_PWMA01 LPUART7_TX LPSPI1_PCS1 CSI_DATA22 GPIO4_IO31 ENET2_TDATA01 ~ ~ ~ - D30 = PC23 // [EMC_37]: SEMC_DATA15 XBAR1_IN23 GPT1_COMPARE3 SAI3_MCLK CSI_DATA16 GPIO3_IO23 USDHC2_WP ENET2_RX_EN FLEXCAN3_RX ~ - D31 = PC22 // [EMC_36]: SEMC_DATA14 XBAR1_IN22 GPT1_COMPARE2 SAI3_TX_DATA CSI_DATA17 GPIO3_IO22 USDHC1_WP ENET2_RDATA01 FLEXCAN3_TX ~ - D32 = PB12 // [B0_12]: LCD_DATA08 XBAR1_INOUT10 ARM_TRACE_CLK SAI1_TX_DATA01 FLEXIO2_FLEXIO12 GPIO2_IO12 SRC_BOOT_CFG08 ENET2_TDATA00 ~ ~ - D33 = PD7 // [EMC_07]: SEMC_DATA07 FLEXPWM2_PWMB00 SAI2_MCLK XBAR1_INOUT09 FLEXIO1_FLEXIO07 GPIO4_IO07 ~ ~ ~ ~ - D34 = PB29 // [B1_13]: WDOG1_B LPUART5_RX CSI_VSYNC ENET_1588_EVENT0_OUT FLEXIO2_FLEXIO29 GPIO2_IO29 USDHC1_WP SEMC_DQS4 FLEXIO3_FLEXIO29 ~ - D35 = PB28 // [B1_12]: LPUART5_TX CSI_PIXCLK ENET_1588_EVENT0_IN FLEXIO2_FLEXIO28 GPIO2_IO28 USDHC1_CD_B FLEXIO3_FLEXIO28 ~ ~ ~ - D36 = PB18 // [B1_02]: LCD_DATA14 XBAR1_INOUT16 LPSPI4_PCS2 SAI1_TX_BCLK FLEXIO2_FLEXIO18 GPIO2_IO18 FLEXPWM2_PWMA03 ENET2_RDATA01 FLEXIO3_FLEXIO18 ~ - D37 = PB19 // [B1_03]: LCD_DATA15 XBAR1_INOUT17 LPSPI4_PCS1 SAI1_TX_SYNC FLEXIO2_FLEXIO19 GPIO2_IO19 FLEXPWM2_PWMB03 ENET2_RX_EN FLEXIO3_FLEXIO19 ~ - D38 = PA28 // [AD_B1_12]: FLEXSPIA_DATA01 ACMP_OUT00 LPSPI3_PCS0 SAI1_RX_DATA00 CSI_DATA05 GPIO1_IO28 USDHC2_DATA4 KPP_ROW01 ENET2_1588_EVENT2_OUT FLEXIO3_FLEXIO12 - D39 = PA29 // [AD_B1_13]: FLEXSPIA_DATA00 ACMP_OUT01 LPSPI3_SDI SAI1_TX_DATA00 CSI_DATA04 GPIO1_IO29 USDHC2_DATA5 KPP_COL01 ENET2_1588_EVENT2_IN FLEXIO3_FLEXIO13 - D40 = PA20 // [AD_B1_04]: FLEXSPIB_DATA03 ENET_MDC LPUART3_CTS_B SPDIF_SR_CLK CSI_PIXCLK GPIO1_IO20 USDHC2_DATA0 KPP_ROW05 GPT2_CAPTURE2 FLEXIO3_FLEXIO04 - D41 = PA21 // [AD_B1_05]: FLEXSPIB_DATA02 ENET_MDIO LPUART3_RTS_B SPDIF_OUT CSI_MCLK GPIO1_IO21 USDHC2_DATA1 KPP_COL05 GPT2_COMPARE1 FLEXIO3_FLEXIO05 - D42 = PC15 // [SD_B0_03]: USDHC1_DATA1 FLEXPWM1_PWMB01 LPUART8_RTS_B XBAR1_INOUT07 LPSPI1_SDI GPIO3_IO15 ENET2_RDATA00 SEMC_CLK6 ~ ~ - D43 = PC14 // [SD_B0_02]: USDHC1_DATA0 FLEXPWM1_PWMA01 LPUART8_CTS_B XBAR1_INOUT06 LPSPI1_SDO GPIO3_IO14 ENET2_RX_ER SEMC_CLK5 ~ ~ - D44 = PC13 // [SD_B0_01]: USDHC1_CLK FLEXPWM1_PWMB00 LPI2C3_SDA XBAR1_INOUT05 LPSPI1_PCS0 GPIO3_IO13 FLEXSPIB_SS1_B ENET2_TX_CLK ENET2_REF_CLK2 ~ - D45 = PC12 // [SD_B0_00]: USDHC1_CMD FLEXPWM1_PWMA00 LPI2C3_SCL XBAR1_INOUT04 LPSPI1_SCK GPIO3_IO12 FLEXSPIA_SS1_B ENET2_TX_EN SEMC_DQS4 ~ - D46 = PC17 // [SD_B0_05]: USDHC1_DATA3 FLEXPWM1_PWMB02 LPUART8_RX XBAR1_INOUT09 FLEXSPIB_DQS GPIO3_IO17 CCM_CLKO2 ENET2_RX_EN ~ ~ - D47 = PC16 // [SD_B0_04]: USDHC1_DATA2 FLEXPWM1_PWMA02 LPUART8_TX XBAR1_INOUT08 FLEXSPIB_SS0_B GPIO3_IO16 CCM_CLKO1 ENET2_RDATA01 ~ ~ - D48 = PD24 // [EMC_24]: SEMC_CAS FLEXPWM1_PWMB00 LPUART5_RX ENET_TX_EN GPT1_CAPTURE1 GPIO4_IO24 FLEXSPI2_A_SS0_B ~ ~ ~ - D49 = PD27 // [EMC_27]: SEMC_CKE FLEXPWM1_PWMA02 LPUART5_RTS_B LPSPI1_SCK FLEXIO1_FLEXIO13 GPIO4_IO27 FLEXSPI2_A_DATA01 ~ ~ ~ - D50 = PD28 // [EMC_28]: SEMC_WE FLEXPWM1_PWMB02 LPUART5_CTS_B LPSPI1_SDO FLEXIO1_FLEXIO14 GPIO4_IO28 FLEXSPI2_A_DATA02 ~ ~ ~ - D51 = PD22 // [EMC_22]: SEMC_BA1 FLEXPWM3_PWMB03 LPI2C3_SCL ENET_TDATA00 QTIMER2_TIMER3 GPIO4_IO22 FLEXSPI2_A_SS1_B ~ ~ ~ - D52 = PD26 // [EMC_26]: SEMC_CLK FLEXPWM1_PWMB01 LPUART6_RX ENET_RX_ER FLEXIO1_FLEXIO12 GPIO4_IO26 FLEXSPI2_A_DATA00 ~ ~ ~ - D53 = PD25 // [EMC_25]: SEMC_RAS FLEXPWM1_PWMA01 LPUART6_TX ENET_TX_CLK ENET_REF_CLK GPIO4_IO25 FLEXSPI2_A_SCLK ~ ~ ~ - D54 = PD29 // [EMC_29]: SEMC_CS0 FLEXPWM3_PWMA00 LPUART6_RTS_B LPSPI1_SDI FLEXIO1_FLEXIO15 GPIO4_IO29 FLEXSPI2_A_DATA03 ~ ~ ~ -) - -// Analog pins -const ( - // = Pin // Dig | [Pad] {ADC1/ADC2} - A0 = PA18 // D14 | [AD_B1_02] { 7 / 7 } - A1 = PA19 // D15 | [AD_B1_03] { 8 / 8 } - A2 = PA23 // D16 | [AD_B1_07] { 12 / 12 } - A3 = PA22 // D17 | [AD_B1_06] { 11 / 11 } - A4 = PA17 // D18 | [AD_B1_01] { 6 / 6 } - A5 = PA16 // D19 | [AD_B1_00] { 5 / 5 } - A6 = PA26 // D20 | [AD_B1_10] { 15 / 15 } - A7 = PA27 // D21 | [AD_B1_11] { 0 / 0 } - A8 = PA24 // D22 | [AD_B1_08] { 13 / 13 } - A9 = PA25 // D23 | [AD_B1_09] { 14 / 14 } - A10 = PA12 // D24 | [AD_B0_12] { 1 / - } - A11 = PA13 // D25 | [AD_B0_13] { 2 / - } - A12 = PA30 // D26 | [AD_B1_14] { - / 3 } - A13 = PA31 // D27 | [AD_B1_15] { - / 4 } - A14 = PA28 // D38 | [AD_B1_12] { ? / ? } // FIXME - A15 = PA29 // D39 | [AD_B1_13] { ? / ? } // FIXME - A16 = PA20 // D40 | [AD_B1_04] { ? / ? } // FIXME - A17 = PA21 // D41 | [AD_B1_05] { ? / ? } // FIXME -) - -// Default peripheral pins -const ( - LED = D13 - - UART_RX_PIN = UART1_RX_PIN // D0 - UART_TX_PIN = UART1_TX_PIN // D1 - - SPI_SDI_PIN = SPI1_SDI_PIN // D12 - SPI_SDO_PIN = SPI1_SDO_PIN // D11 - SPI_SCK_PIN = SPI1_SCK_PIN // D13 - SPI_CS_PIN = SPI1_CS_PIN // D10 - - I2C_SDA_PIN = I2C1_SDA_PIN // D18/A4 - I2C_SCL_PIN = I2C1_SCL_PIN // D19/A5 -) - -// Default peripherals -var ( - DefaultUART = UART1 -) - -func init() { - // register any interrupt handlers for this board's peripherals - _UART1.Interrupt = interrupt.New(nxp.IRQ_LPUART6, _UART1.handleInterrupt) - _UART2.Interrupt = interrupt.New(nxp.IRQ_LPUART4, _UART2.handleInterrupt) - _UART3.Interrupt = interrupt.New(nxp.IRQ_LPUART2, _UART3.handleInterrupt) - _UART4.Interrupt = interrupt.New(nxp.IRQ_LPUART3, _UART4.handleInterrupt) - _UART5.Interrupt = interrupt.New(nxp.IRQ_LPUART8, _UART5.handleInterrupt) - _UART6.Interrupt = interrupt.New(nxp.IRQ_LPUART1, _UART6.handleInterrupt) - _UART7.Interrupt = interrupt.New(nxp.IRQ_LPUART7, _UART7.handleInterrupt) - _UART8.Interrupt = interrupt.New(nxp.IRQ_LPUART5, _UART8.handleInterrupt) -} - -// #=====================================================# -// | UART | -// #===========#===========#=============#===============# -// | Interface | Hardware | Clock(Freq) | RX/TX : Alt | -// #===========#===========#=============#=========-=====# -// | UART1 | LPUART6 | OSC(24 MHz) | D0/D1 : 2/2 | -// | UART2 | LPUART4 | OSC(24 MHz) | D7/D8 : 2/2 | -// | UART3 | LPUART2 | OSC(24 MHz) | D15/D14 : 2/2 | -// | UART4 | LPUART3 | OSC(24 MHz) | D16/D17 : 2/2 | -// | UART5 | LPUART8 | OSC(24 MHz) | D21/D20 : 2/2 | -// | UART6 | LPUART1 | OSC(24 MHz) | D25/D24 : 2/2 | -// | UART7 | LPUART7 | OSC(24 MHz) | D28/D29 : 2/2 | -// | UART8 | LPUART5 | OSC(24 MHz) | D34/D35 : 1/1 | -// #===========#===========#=============#=========-=====# -const ( - UART1_RX_PIN = D0 - UART1_TX_PIN = D1 - - UART2_RX_PIN = D7 - UART2_TX_PIN = D8 - - UART3_RX_PIN = D15 - UART3_TX_PIN = D14 - - UART4_RX_PIN = D16 - UART4_TX_PIN = D17 - - UART5_RX_PIN = D21 - UART5_TX_PIN = D20 - - UART6_RX_PIN = D25 - UART6_TX_PIN = D24 - - UART7_RX_PIN = D28 - UART7_TX_PIN = D29 - - UART8_RX_PIN = D34 - UART8_TX_PIN = D35 -) - -var ( - UART1 = &_UART1 - _UART1 = UART{ - Bus: nxp.LPUART6, - Buffer: NewRingBuffer(), - txBuffer: NewRingBuffer(), - muxRX: muxSelect{ // D0 (PA3 [AD_B0_03]) - mux: nxp.IOMUXC_LPUART6_RX_SELECT_INPUT_DAISY_GPIO_AD_B0_03_ALT2, - sel: &nxp.IOMUXC.LPUART6_RX_SELECT_INPUT, - }, - muxTX: muxSelect{ // D1 (PA2 [AD_B0_02]) - mux: nxp.IOMUXC_LPUART6_TX_SELECT_INPUT_DAISY_GPIO_AD_B0_02_ALT2, - sel: &nxp.IOMUXC.LPUART6_TX_SELECT_INPUT, - }, - } - UART2 = &_UART2 - _UART2 = UART{ - Bus: nxp.LPUART4, - Buffer: NewRingBuffer(), - txBuffer: NewRingBuffer(), - muxRX: muxSelect{ // D7 (PB17 [B1_01]) - mux: nxp.IOMUXC_LPUART4_RX_SELECT_INPUT_DAISY_GPIO_B1_01_ALT2, - sel: &nxp.IOMUXC.LPUART4_RX_SELECT_INPUT, - }, - muxTX: muxSelect{ // D8 (PB16 [B1_00]) - mux: nxp.IOMUXC_LPUART4_TX_SELECT_INPUT_DAISY_GPIO_B1_00_ALT2, - sel: &nxp.IOMUXC.LPUART4_TX_SELECT_INPUT, - }, - } - UART3 = &_UART3 - _UART3 = UART{ - Bus: nxp.LPUART2, - Buffer: NewRingBuffer(), - txBuffer: NewRingBuffer(), - muxRX: muxSelect{ // D15 (PA19 [AD_B1_03]) - mux: nxp.IOMUXC_LPUART2_RX_SELECT_INPUT_DAISY_GPIO_AD_B1_03_ALT2, - sel: &nxp.IOMUXC.LPUART2_RX_SELECT_INPUT, - }, - muxTX: muxSelect{ // D14 (PA18 [AD_B1_02]) - mux: nxp.IOMUXC_LPUART2_TX_SELECT_INPUT_DAISY_GPIO_AD_B1_02_ALT2, - sel: &nxp.IOMUXC.LPUART2_TX_SELECT_INPUT, - }, - } - UART4 = &_UART4 - _UART4 = UART{ - Bus: nxp.LPUART3, - Buffer: NewRingBuffer(), - txBuffer: NewRingBuffer(), - muxRX: muxSelect{ // D16 (PA23 [AD_B1_07]) - mux: nxp.IOMUXC_LPUART3_RX_SELECT_INPUT_DAISY_GPIO_AD_B1_07_ALT2, - sel: &nxp.IOMUXC.LPUART3_RX_SELECT_INPUT, - }, - muxTX: muxSelect{ // D17 (PA22 [AD_B1_06]) - mux: nxp.IOMUXC_LPUART3_TX_SELECT_INPUT_DAISY_GPIO_AD_B1_06_ALT2, - sel: &nxp.IOMUXC.LPUART3_TX_SELECT_INPUT, - }, - } - UART5 = &_UART5 - _UART5 = UART{ - Bus: nxp.LPUART8, - Buffer: NewRingBuffer(), - txBuffer: NewRingBuffer(), - muxRX: muxSelect{ // D21 (PA27 [AD_B1_11]) - mux: nxp.IOMUXC_LPUART8_RX_SELECT_INPUT_DAISY_GPIO_AD_B1_11_ALT2, - sel: &nxp.IOMUXC.LPUART8_RX_SELECT_INPUT, - }, - muxTX: muxSelect{ // D20 (PA26 [AD_B1_10]) - mux: nxp.IOMUXC_LPUART8_TX_SELECT_INPUT_DAISY_GPIO_AD_B1_10_ALT2, - sel: &nxp.IOMUXC.LPUART8_TX_SELECT_INPUT, - }, - } - UART6 = &_UART6 - _UART6 = UART{ - Bus: nxp.LPUART1, - Buffer: NewRingBuffer(), - txBuffer: NewRingBuffer(), - // LPUART1 not connected via IOMUXC - // RX: D24 (PA12 [AD_B0_12]) - // TX: D25 (PA13 [AD_B0_13]) - } - UART7 = &_UART7 - _UART7 = UART{ - Bus: nxp.LPUART7, - Buffer: NewRingBuffer(), - txBuffer: NewRingBuffer(), - muxRX: muxSelect{ // D28 (PC18 [EMC_32]) - mux: nxp.IOMUXC_LPUART7_RX_SELECT_INPUT_DAISY_GPIO_EMC_32_ALT2, - sel: &nxp.IOMUXC.LPUART7_RX_SELECT_INPUT, - }, - muxTX: muxSelect{ // D29 (PD31 [EMC_31]) - mux: nxp.IOMUXC_LPUART7_TX_SELECT_INPUT_DAISY_GPIO_EMC_31_ALT2, - sel: &nxp.IOMUXC.LPUART7_TX_SELECT_INPUT, - }, - } - UART8 = &_UART8 - _UART8 = UART{ - Bus: nxp.LPUART5, - Buffer: NewRingBuffer(), - txBuffer: NewRingBuffer(), - muxRX: muxSelect{ // D34 (PB29 [B1_13]) - mux: nxp.IOMUXC_LPUART5_RX_SELECT_INPUT_DAISY_GPIO_B1_13_ALT1, - sel: &nxp.IOMUXC.LPUART5_RX_SELECT_INPUT, - }, - muxTX: muxSelect{ // D35 (PB28 [B1_12]) - mux: nxp.IOMUXC_LPUART5_TX_SELECT_INPUT_DAISY_GPIO_B1_12_ALT1, - sel: &nxp.IOMUXC.LPUART5_TX_SELECT_INPUT, - }, - } -) - -// #===========#==========#===============#===========================# -// | Interface | Hardware | Clock(Freq) | SDI/SDO/SCK/CS : Alt | -// #===========#==========#===============#=================-=========# -// | SPI1 | LPSPI4 | PLL2(132 MHz) | D12/D11/D13/D10 : 3/3/3/3 | -// | SPI2 | LPSPI3 | PLL2(132 MHz) | D1/D26/D27/D0 : 7/2/2/7 | -// | SPI3 | LPSPI1 | PLL2(132 MHz) | D34/D35/D37/D36 : 4/4/4/4 | -// #===========#==========#===============#=================-=========# -const ( - SPI1_SDI_PIN = D12 - SPI1_SDO_PIN = D11 - SPI1_SCK_PIN = D13 - SPI1_CS_PIN = D10 - - SPI2_SDI_PIN = D1 - SPI2_SDO_PIN = D26 - SPI2_SCK_PIN = D27 - SPI2_CS_PIN = D0 - - SPI3_SDI_PIN = D34 - SPI3_SDO_PIN = D35 - SPI3_SCK_PIN = D37 - SPI3_CS_PIN = D36 -) - -// #====================================================# -// | I2C | -// #===========#==========#=============#===============# -// | Interface | Hardware | Clock(Freq) | SDA/SCL : Alt | -// #===========#==========#=============#=========-=====# -// | I2C1 | LPI2C1 | OSC(24 MHz) | D18/D19 : 3/3 | -// | I2C2 | LPI2C3 | OSC(24 MHz) | D17/D16 : 1/1 | -// | I2C3 | LPI2C4 | OSC(24 MHz) | D25/D24 : 0/0 | -// #===========#==========#=============#=========-=====# -const ( - I2C1_SDA_PIN = D18 - I2C1_SCL_PIN = D19 - - I2C2_SDA_PIN = D17 - I2C2_SCL_PIN = D16 - - I2C3_SDA_PIN = D25 - I2C3_SCL_PIN = D24 -) diff --git a/emb/machine/board_thingplus_rp2040.go b/emb/machine/board_thingplus_rp2040.go deleted file mode 100644 index 48292d2..0000000 --- a/emb/machine/board_thingplus_rp2040.go +++ /dev/null @@ -1,103 +0,0 @@ -//go:build thingplus_rp2040 - -package machine - -// Onboard crystal oscillator frequency, in MHz. -const xoscFreq = 12 // MHz - -// GPIO Pins -const ( - GP0 Pin = GPIO0 // TX - GP1 Pin = GPIO1 // RX - GP2 Pin = GPIO2 // SCK - GP3 Pin = GPIO3 // COPI - GP4 Pin = GPIO4 // CIPO - - GP6 Pin = GPIO6 // SDA - GP7 Pin = GPIO7 // SCL (connected to GPIO23 as well) - GP8 Pin = GPIO8 // WS2812 RGB LED - GP9 Pin = GPIO9 // muSDcard DATA3 / CS - GP10 Pin = GPIO10 // muSDcard DATA2 - GP11 Pin = GPIO11 // muSDcard DATA1 - GP12 Pin = GPIO12 // muSDcard DATA0 / CIPO - - GP14 Pin = GPIO14 // muSDcard CLK /SCLK - GP15 Pin = GPIO15 // muSDcard CMD / COPI - GP16 Pin = GPIO16 // 16 - GP17 Pin = GPIO17 // 17 - GP18 Pin = GPIO18 // 18 - GP19 Pin = GPIO19 // 19 - GP20 Pin = GPIO20 // 20 - GP21 Pin = GPIO21 // 21 - GP22 Pin = GPIO22 // 22 - GP23 Pin = GPIO23 // Connected to GPIO7 - GP25 Pin = GPIO25 // Status blue LED - GP26 Pin = GPIO26 // ADC0 - GP27 Pin = GPIO27 // ADC1 - GP28 Pin = GPIO28 // ADC2 - GP29 Pin = GPIO29 // ADC3 -) - -// Analog pins -const ( - A0 = GPIO26 - A1 = GPIO27 - A2 = GPIO28 - A3 = GPIO29 -) - -// Onboard LEDs -const ( - LED = GPIO25 - WS2812 = GPIO8 -) - -// I2C Pins. -const ( - I2C0_SCL_PIN = GPIO6 // N/A - I2C0_SDA_PIN = GPIO7 // N/A - - I2C1_SDA_PIN = GPIO6 - I2C1_SCL_PIN = GPIO7 - - SDA_PIN = I2C1_SDA_PIN - SCL_PIN = I2C1_SCL_PIN -) - -// SPI default pins -const ( - // Default Serial Clock Bus 0 for SPI communications - SPI0_SCK_PIN = GPIO2 - // Default Serial Out Bus 0 for SPI communications - SPI0_SDO_PIN = GPIO3 // Tx - // Default Serial In Bus 0 for SPI communications - SPI0_SDI_PIN = GPIO4 // Rx - - // Default Serial Clock Bus 1 for SPI communications to muSDcard - SPI1_SCK_PIN = GPIO14 - // Default Serial Out Bus 1 for SPI communications to muSDcard - SPI1_SDO_PIN = GPIO15 // Tx - // Default Serial In Bus 1 for SPI communications to muSDcard - SPI1_SDI_PIN = GPIO12 // Rx -) - -// UART pins -const ( - UART0_TX_PIN = GPIO0 - UART0_RX_PIN = GPIO1 - UART_TX_PIN = UART0_TX_PIN - UART_RX_PIN = UART0_RX_PIN -) - -var DefaultUART = UART0 - -// USB identifiers -const ( - usb_STRING_PRODUCT = "Thing Plus RP2040" - usb_STRING_MANUFACTURER = "SparkFun" -) - -var ( - usb_VID uint16 = 0x1B4F - usb_PID uint16 = 0x0026 -) diff --git a/emb/machine/board_thumby.go b/emb/machine/board_thumby.go deleted file mode 100644 index f89a8b7..0000000 --- a/emb/machine/board_thumby.go +++ /dev/null @@ -1,76 +0,0 @@ -//go:build thumby - -// This contains the pin mappings for the Thumby. -// -// https://thumby.us/ -package machine - -const ( - THUMBY_SCK_PIN = I2C1_SDA_PIN - THUMBY_SDA_PIN = I2C1_SCL_PIN - - THUMBY_CS_PIN = GPIO16 - THUMBY_DC_PIN = GPIO17 - THUMBY_RESET_PIN = GPIO20 - - THUMBY_LINK_TX_PIN = UART0_TX_PIN - THUMBY_LINK_RX_PIN = UART0_RX_PIN - THUMBY_LINK_PU_PIN = GPIO2 - - THUMBY_BTN_LDPAD_PIN = GPIO3 - THUMBY_BTN_RDPAD_PIN = GPIO5 - THUMBY_BTN_UDPAD_PIN = GPIO4 - THUMBY_BTN_DDPAD_PIN = GPIO6 - THUMBY_BTN_B_PIN = GPIO24 - THUMBY_BTN_A_PIN = GPIO27 - - THUMBY_AUDIO_PIN = GPIO28 - - THUMBY_SCREEN_RESET_PIN = GPIO20 -) - -// I2C pins -const ( - I2C0_SDA_PIN Pin = NoPin - I2C0_SCL_PIN Pin = NoPin - - I2C1_SDA_PIN Pin = GPIO18 - I2C1_SCL_PIN Pin = GPIO19 -) - -// SPI pins -const ( - SPI0_SCK_PIN = GPIO18 - SPI0_SDO_PIN = GPIO19 - SPI0_SDI_PIN = GPIO16 - - SPI1_SCK_PIN = NoPin - SPI1_SDO_PIN = NoPin - SPI1_SDI_PIN = NoPin -) - -// Onboard crystal oscillator frequency, in MHz. -const ( - xoscFreq = 12 // MHz -) - -// USB CDC identifiers -const ( - usb_STRING_PRODUCT = "Thumby" - usb_STRING_MANUFACTURER = "TinyCircuits" -) - -var ( - usb_VID uint16 = 0x2E8A - usb_PID uint16 = 0x0005 -) - -// UART pins -const ( - UART0_TX_PIN = GPIO0 - UART0_RX_PIN = GPIO1 - UART_TX_PIN = UART0_TX_PIN - UART_RX_PIN = UART0_RX_PIN -) - -var DefaultUART = UART0 diff --git a/emb/machine/board_tiny2350.go b/emb/machine/board_tiny2350.go deleted file mode 100644 index f04fa06..0000000 --- a/emb/machine/board_tiny2350.go +++ /dev/null @@ -1,82 +0,0 @@ -//go:build tiny2350 - -package machine - -// GPIO pins -const ( - GP0 Pin = GPIO0 - GP1 Pin = GPIO1 - GP2 Pin = GPIO2 - GP3 Pin = GPIO3 - GP4 Pin = GPIO4 - GP5 Pin = GPIO5 - GP6 Pin = GPIO6 - GP7 Pin = GPIO7 - GP12 Pin = GPIO12 - GP13 Pin = GPIO13 - GP18 Pin = GPIO18 - GP19 Pin = GPIO19 - GP20 Pin = GPIO20 - GP26 Pin = GPIO26 - GP27 Pin = GPIO27 - GP28 Pin = GPIO28 - GP29 Pin = GPIO29 - - // Onboard LED - LED_RED Pin = GPIO18 - LED_GREEN Pin = GPIO19 - LED_BLUE Pin = GPIO20 - LED = LED_RED - - // Onboard crystal oscillator frequency, in MHz. - xoscFreq = 12 // MHz -) - -// I2C Default pins on Tiny2350. -const ( - I2C0_SDA_PIN = GP12 - I2C0_SCL_PIN = GP13 - - I2C1_SDA_PIN = GP2 - I2C1_SCL_PIN = GP3 -) - -// SPI default pins -const ( - // Default Serial Clock Bus 0 for SPI communications - SPI0_SCK_PIN = GPIO6 - // Default Serial Out Bus 0 for SPI communications - SPI0_SDO_PIN = GPIO7 // Tx - // Default Serial In Bus 0 for SPI communications - SPI0_SDI_PIN = GPIO4 // Rx - - // Default Serial Clock Bus 1 for SPI communications - SPI1_SCK_PIN = GPIO26 - // Default Serial Out Bus 1 for SPI communications - SPI1_SDO_PIN = GPIO27 // Tx - // Default Serial In Bus 1 for SPI communications - SPI1_SDI_PIN = GPIO28 // Rx -) - -// UART pins -const ( - UART0_TX_PIN = GPIO0 - UART0_RX_PIN = GPIO1 - UART1_TX_PIN = GPIO4 - UART1_RX_PIN = GPIO5 - UART_TX_PIN = UART0_TX_PIN - UART_RX_PIN = UART0_RX_PIN -) - -var DefaultUART = UART0 - -// USB identifiers -const ( - usb_STRING_PRODUCT = "Tiny2350" - usb_STRING_MANUFACTURER = "Pimoroni" -) - -var ( - usb_VID uint16 = 0x2E8A - usb_PID uint16 = 0x000F -) diff --git a/emb/machine/board_trinket.go b/emb/machine/board_trinket.go deleted file mode 100644 index 089eadb..0000000 --- a/emb/machine/board_trinket.go +++ /dev/null @@ -1,88 +0,0 @@ -//go:build sam && atsamd21 && trinket_m0 - -package machine - -// used to reset into bootloader -const resetMagicValue = 0xf01669ef - -// GPIO Pins -const ( - D0 = PA08 // PWM available - D1 = PA02 - D2 = PA09 // PWM available - D3 = PA07 // PWM available / UART0 RX - D4 = PA06 // PWM available / UART0 TX - D13 = PA10 // LED -) - -// Analog pins -const ( - A0 = D1 - A1 = D2 - A2 = D0 - A3 = D3 - A4 = D4 -) - -const ( - LED = D13 -) - -// USBCDC pins -const ( - USBCDC_DM_PIN = PA24 - USBCDC_DP_PIN = PA25 -) - -// UART1 pins -const ( - UART_TX_PIN = D4 - UART_RX_PIN = D3 -) - -// UART1 on the Trinket M0. -var UART1 = &sercomUSART0 - -// SPI pins -const ( - SPI0_SCK_PIN = D3 - SPI0_SDO_PIN = D4 - SPI0_SDI_PIN = D2 -) - -// SPI on the Trinket M0. -var SPI0 = sercomSPIM0 - -// I2C pins -const ( - SDA_PIN = D0 // SDA - SCL_PIN = D2 // SCL -) - -// I2C on the Trinket M0. -var ( - I2C0 = sercomI2CM2 -) - -// I2S pins -const ( - I2S_SCK_PIN = PA10 - I2S_SDO_PIN = PA08 - I2S_SDI_PIN = NoPin // TODO: figure out what this is on Trinket M0. - I2S_WS_PIN = NoPin // TODO: figure out what this is on Trinket M0. -) - -// USB CDC identifiers -const ( - usb_STRING_PRODUCT = "Adafruit Trinket M0" - usb_STRING_MANUFACTURER = "Adafruit" -) - -var ( - usb_VID uint16 = 0x239A - usb_PID uint16 = 0x801E -) - -var ( - DefaultUART = UART1 -) diff --git a/emb/machine/board_trinkey_qt2040.go b/emb/machine/board_trinkey_qt2040.go deleted file mode 100644 index 1a49c6d..0000000 --- a/emb/machine/board_trinkey_qt2040.go +++ /dev/null @@ -1,62 +0,0 @@ -//go:build trinkey_qt2040 - -// This file contains the pin mappings for the Adafruit Trinkey QT2040 board. -// -// The Trinkey QT2040 is a small development board based on the RP2040 which -// plugs into a USB A port. The board has a minimal pinout: an integrated -// NeoPixel LED and a STEMMA QT I2C port. -// -// - Product: https://www.adafruit.com/product/5056 -// - Overview: https://learn.adafruit.com/adafruit-trinkey-qt2040 -// - Pinouts: https://learn.adafruit.com/adafruit-trinkey-qt2040/pinouts -// - Datasheets: https://learn.adafruit.com/adafruit-trinkey-qt2040/downloads - -package machine - -// Onboard crystal oscillator frequency, in MHz -const xoscFreq = 12 // MHz - -// Onboard LEDs -const ( - NEOPIXEL = GPIO27 - WS2812 = NEOPIXEL -) - -// I2C pins -const ( - I2C0_SDA_PIN = GPIO16 - I2C0_SCL_PIN = GPIO17 - - I2C1_SDA_PIN = NoPin - I2C1_SCL_PIN = NoPin -) - -// SPI pins -const ( - SPI0_SCK_PIN = NoPin - SPI0_SDO_PIN = NoPin - SPI0_SDI_PIN = NoPin - - SPI1_SCK_PIN = NoPin - SPI1_SDO_PIN = NoPin - SPI1_SDI_PIN = NoPin -) - -// UART pins -const ( - UART0_TX_PIN = NoPin - UART0_RX_PIN = NoPin - UART_TX_PIN = UART0_TX_PIN - UART_RX_PIN = UART0_RX_PIN -) - -// USB identifiers -const ( - usb_STRING_PRODUCT = "Trinkey QT2040" - usb_STRING_MANUFACTURER = "Adafruit" -) - -var ( - usb_VID uint16 = 0x239a - usb_PID uint16 = 0x8109 -) diff --git a/emb/machine/board_tufty2040.go b/emb/machine/board_tufty2040.go deleted file mode 100644 index 57d244f..0000000 --- a/emb/machine/board_tufty2040.go +++ /dev/null @@ -1,85 +0,0 @@ -//go:build tufty2040 - -// This contains the pin mappings for the Badger 2040 Connect board. -// -// For more information, see: https://shop.pimoroni.com/products/tufty-2040 -// Also -// - Tufty 2040 schematic: https://cdn.shopify.com/s/files/1/0174/1800/files/tufty_schematic.pdf?v=1655385675 -package machine - -const ( - LED Pin = GPIO25 - - BUTTON_A Pin = GPIO7 - BUTTON_B Pin = GPIO8 - BUTTON_C Pin = GPIO9 - BUTTON_UP Pin = GPIO22 - BUTTON_DOWN Pin = GPIO6 - BUTTON_USER Pin = GPIO23 - - LCD_BACKLIGHT Pin = GPIO2 - LCD_CS Pin = GPIO10 - LCD_DC Pin = GPIO11 - LCD_WR Pin = GPIO12 - LCD_RD Pin = GPIO13 - LCD_DB0 Pin = GPIO14 - LCD_DB1 Pin = GPIO15 - LCD_DB2 Pin = GPIO16 - LCD_DB3 Pin = GPIO17 - LCD_DB4 Pin = GPIO18 - LCD_DB5 Pin = GPIO19 - LCD_DB6 Pin = GPIO20 - LCD_DB7 Pin = GPIO21 - - VBUS_DETECT Pin = GPIO24 - BATTERY Pin = GPIO29 - USER_LED Pin = GPIO25 - LIGHT_SENSE Pin = GPIO26 - SENSOR_POWER Pin = GPIO27 -) - -// I2C pins -const ( - I2C0_SDA_PIN Pin = GPIO4 - I2C0_SCL_PIN Pin = GPIO5 - - I2C1_SDA_PIN Pin = NoPin - I2C1_SCL_PIN Pin = NoPin -) - -// SPI pins. -const ( - SPI0_SCK_PIN Pin = NoPin - SPI0_SDO_PIN Pin = NoPin - SPI0_SDI_PIN Pin = NoPin - - SPI1_SCK_PIN Pin = NoPin - SPI1_SDO_PIN Pin = NoPin - SPI1_SDI_PIN Pin = NoPin -) - -// Onboard crystal oscillator frequency, in MHz. -const ( - xoscFreq = 12 // MHz -) - -// USB CDC identifiers -const ( - usb_STRING_PRODUCT = "Tufty 2040" - usb_STRING_MANUFACTURER = "Pimoroni" -) - -var ( - usb_VID uint16 = 0x2e8a - usb_PID uint16 = 0x1002 -) - -// UART pins -const ( - UART0_TX_PIN = GPIO0 - UART0_RX_PIN = GPIO1 - UART_TX_PIN = UART0_TX_PIN - UART_RX_PIN = UART0_RX_PIN -) - -var DefaultUART = UART0 diff --git a/emb/machine/board_waveshare-rp2040-zero.go b/emb/machine/board_waveshare-rp2040-zero.go deleted file mode 100644 index 00ddc53..0000000 --- a/emb/machine/board_waveshare-rp2040-zero.go +++ /dev/null @@ -1,104 +0,0 @@ -//go:build waveshare_rp2040_zero - -// This file contains the pin mappings for the Waveshare RP2040-Zero boards. -// -// Waveshare RP2040-Zero is a microcontroller using the Raspberry Pi RP2040 chip. -// -// - https://www.waveshare.com/wiki/RP2040-Zero -package machine - -// Digital Pins -const ( - D0 Pin = GPIO0 - D1 Pin = GPIO1 - D2 Pin = GPIO2 - D3 Pin = GPIO3 - D4 Pin = GPIO4 - D5 Pin = GPIO5 - D6 Pin = GPIO6 - D7 Pin = GPIO7 - D8 Pin = GPIO8 - D9 Pin = GPIO9 - D10 Pin = GPIO10 - D11 Pin = GPIO11 - D12 Pin = GPIO12 - D13 Pin = GPIO13 - D14 Pin = GPIO14 - D15 Pin = GPIO15 - D16 Pin = GPIO16 - D17 Pin = GPIO17 - D18 Pin = GPIO18 - D19 Pin = GPIO19 - D20 Pin = GPIO20 - D21 Pin = GPIO21 - D22 Pin = GPIO22 - D23 Pin = GPIO23 - D24 Pin = GPIO24 - D25 Pin = GPIO25 - D26 Pin = GPIO26 - D27 Pin = GPIO27 - D28 Pin = GPIO28 - D29 Pin = GPIO29 -) - -// Analog pins -const ( - A0 Pin = D26 - A1 Pin = D27 - A2 Pin = D28 - A3 Pin = D29 -) - -// Onboard LEDs -const ( - NEOPIXEL = GPIO16 - WS2812 = GPIO16 -) - -// I2C pins -const ( - I2C0_SDA_PIN Pin = D0 - I2C0_SCL_PIN Pin = D1 - - I2C1_SDA_PIN Pin = D2 - I2C1_SCL_PIN Pin = D3 -) - -// SPI pins -const ( - SPI0_SCK_PIN Pin = D6 - SPI0_SDO_PIN Pin = D3 - SPI0_SDI_PIN Pin = D4 - - SPI1_SCK_PIN Pin = D10 - SPI1_SDO_PIN Pin = D11 - SPI1_SDI_PIN Pin = D12 -) - -// Onboard crystal oscillator frequency, in MHz. -const ( - xoscFreq = 12 // MHz -) - -// UART pins -const ( - UART0_TX_PIN = GPIO0 - UART0_RX_PIN = GPIO1 - UART_TX_PIN = UART0_TX_PIN - UART_RX_PIN = UART0_RX_PIN - UART1_TX_PIN = GPIO8 - UART1_RX_PIN = GPIO9 -) - -var DefaultUART = UART0 - -// USB CDC identifiers -const ( - usb_STRING_PRODUCT = "RP2040-Zero" - usb_STRING_MANUFACTURER = "Waveshare" -) - -var ( - usb_VID uint16 = 0x2e8a - usb_PID uint16 = 0x0003 -) diff --git a/emb/machine/board_waveshare_rp2040_tiny.go b/emb/machine/board_waveshare_rp2040_tiny.go deleted file mode 100644 index a3ef354..0000000 --- a/emb/machine/board_waveshare_rp2040_tiny.go +++ /dev/null @@ -1,121 +0,0 @@ -//go:build waveshare_rp2040_tiny - -// This file contains the pin mappings for the Waveshare RP2040-Tiny boards. -// -// Waveshare RP2040-Tiny is a microcontroller using the Raspberry Pi RP2040 chip. -// -// - https://www.waveshare.com/wiki/RP2040-Tiny -package machine - -// Digital Pins -const ( - GP0 Pin = GPIO0 - GP1 Pin = GPIO1 - GP2 Pin = GPIO2 - GP3 Pin = GPIO3 - GP4 Pin = GPIO4 - GP5 Pin = GPIO5 - GP6 Pin = GPIO6 - GP7 Pin = GPIO7 - GP8 Pin = GPIO8 - GP9 Pin = GPIO9 - GP10 Pin = GPIO10 - GP11 Pin = GPIO11 - GP12 Pin = GPIO12 - GP13 Pin = GPIO13 - GP14 Pin = GPIO14 - GP15 Pin = GPIO15 - GP16 Pin = GPIO16 - GP17 Pin = NoPin - GP18 Pin = NoPin - GP19 Pin = NoPin - GP20 Pin = NoPin - GP21 Pin = NoPin - GP22 Pin = NoPin - GP23 Pin = NoPin - GP24 Pin = GPIO24 - GP25 Pin = GPIO25 - GP26 Pin = GPIO26 - GP27 Pin = GPIO27 - GP28 Pin = GPIO28 - GP29 Pin = GPIO29 -) - -// Analog pins -const ( - A0 Pin = GP26 - A1 Pin = GP27 - A2 Pin = GP28 - A3 Pin = GP29 -) - -// Onboard LEDs -const ( - LED = GP16 - WS2812 = GP16 -) - -// I2C pins -const ( - I2C0_SDA_PIN Pin = GP0 - I2C0_SCL_PIN Pin = GP1 - I2C1_SDA_PIN Pin = GP2 - I2C1_SCL_PIN Pin = GP3 - - // default I2C0 - I2C_SDA_PIN Pin = I2C0_SDA_PIN - I2C_SCL_PIN Pin = I2C0_SCL_PIN -) - -// SPI pins -const ( - SPI0_RX_PIN Pin = GP0 - SPI0_CSN_PIN Pin = GP1 - SPI0_SCK_PIN Pin = GP2 - SPI0_TX_PIN Pin = GP3 - SPI0_SDO_PIN Pin = SPI0_TX_PIN - SPI0_SDI_PIN Pin = SPI0_RX_PIN - - SPI1_RX_PIN Pin = GP8 - SPI1_CSN_PIN Pin = GP9 - SPI1_SCK_PIN Pin = GP10 - SPI1_TX_PIN Pin = GP11 - SPI1_SDO_PIN Pin = SPI1_TX_PIN - SPI1_SDI_PIN Pin = SPI1_RX_PIN - - // default SPI0 - SPI_RX_PIN Pin = SPI0_RX_PIN - SPI_CSN_PIN Pin = SPI0_CSN_PIN - SPI_SCK_PIN Pin = SPI0_SCK_PIN - SPI_TX_PIN Pin = SPI0_TX_PIN - SPI_SDO_PIN Pin = SPI0_TX_PIN - SPI_SDI_PIN Pin = SPI0_RX_PIN -) - -// Onboard crystal oscillator frequency, in MHz. -const ( - xoscFreq = 12 // MHz -) - -// UART pins -const ( - UART0_TX_PIN = GP0 - UART0_RX_PIN = GP1 - UART1_TX_PIN = GP8 - UART1_RX_PIN = GP9 - - // default UART0 - UART_TX_PIN = UART0_TX_PIN - UART_RX_PIN = UART0_RX_PIN -) - -// USB CDC identifiers -const ( - usb_STRING_PRODUCT = "RP2040-Tiny" - usb_STRING_MANUFACTURER = "Waveshare" -) - -var ( - usb_VID uint16 = 0x2e8a - usb_PID uint16 = 0x0003 -) diff --git a/emb/machine/board_wioterminal.go b/emb/machine/board_wioterminal.go deleted file mode 100644 index 6997120..0000000 --- a/emb/machine/board_wioterminal.go +++ /dev/null @@ -1,432 +0,0 @@ -//go:build wioterminal - -package machine - -// used to reset into bootloader -const resetMagicValue = 0xf01669ef - -const ( - ADC0 = A0 - ADC1 = A1 - ADC2 = A2 - ADC3 = A3 - ADC4 = A4 - ADC5 = A5 - ADC6 = A6 - ADC7 = A7 - ADC8 = A8 - - LED = PIN_LED - BUTTON = BUTTON_1 -) - -const ( - // https://github.com/Seeed-Studio/ArduinoCore-samd/blob/master/variants/wio_terminal/variant.h - - // LEDs - PIN_LED_13 = PA15 - PIN_LED_RXL = PA15 - PIN_LED_TXL = PA15 - PIN_LED = PIN_LED_13 - PIN_LED2 = PIN_LED_RXL - PIN_LED3 = PIN_LED_TXL - LED_BUILTIN = PIN_LED_13 - PIN_NEOPIXEL = PA15 - - //Digital PINs - D0 = PB08 - D1 = PB09 - D2 = PA07 - D3 = PB04 - D4 = PB05 - D5 = PB06 - D6 = PA04 - D7 = PB07 - D8 = PA06 - - //Analog PINs - A0 = PB08 // ADC/AIN[0] - A1 = PB09 // ADC/AIN[2] - A2 = PA07 // ADC/AIN[3] - A3 = PB04 // ADC/AIN[4] - A4 = PB05 // ADC/AIN[5] - A5 = PB06 // ADC/AIN[10] - A6 = PA04 // ADC/AIN[10] - A7 = PB07 // ADC/AIN[10] - A8 = PA06 // ADC/AIN[10] - - // 3.3V || 5V - // BCM2 || 5V - // BCM3 || GND - // BCM4 || BCM14 - // GND || BCM15 - // BCM17 || BCM18 - // BCM27 || GND - // BCM22 || BCM23 - // GND || BCM24 - // BCM10 || GND - // BCM9 || BCM25 - // BCM11 || BCM8 - // GND || BCM7 - // BCM0 || BCM1 - // BCM5 || GND - // BCM6 || BCM12 - // BCM13 || GND - // BCM19 || BCM16 - // BCM26 || BCM20 - // GND || BCM21 - - //PIN DEFINE FOR RPI - BCM0 = PA13 // I2C Wire1 - BCM1 = PA12 // I2C Wire1 - BCM2 = PA17 // I2C Wire2 - BCM3 = PA16 // I2C Wire2 - BCM4 = PB14 // GCLK - BCM5 = PB12 // GCLK - BCM6 = PB13 // GCLK - BCM7 = PA05 // DAC1 - BCM8 = PB01 // SPI SS - BCM9 = PB00 // SPI SDI - BCM10 = PB02 // SPI SDO - BCM11 = PB03 // SPI SCK - BCM12 = PB06 - BCM13 = PA04 - BCM14 = PB27 // UART Serial1 - BCM15 = PB26 // UART Serial1 - BCM16 = PB07 - BCM17 = PA02 // DAC0 - BCM18 = PB28 // FPC Digital & AD pins - BCM19 = PA20 // WIO_IR - BCM20 = PA21 // I2S SDO - BCM21 = PA22 // I2S SDI - BCM22 = PB09 - BCM23 = PA07 - BCM24 = PB04 - BCM25 = PB05 - BCM26 = PA06 - BCM27 = PB08 - - // FPC NEW DEFINE - FPC1 = PB28 // FPC Digital & AD pins - FPC2 = PB17 - FPC3 = PB29 - FPC4 = PA14 - FPC5 = PC01 - FPC6 = PC02 - FPC7 = PC03 - FPC8 = PC04 - FPC9 = PC31 - FPC10 = PD00 - - // RPI Analog RPIs - RPI_A0 = PB08 - RPI_A1 = PB09 - RPI_A2 = PA07 - RPI_A3 = PB04 - RPI_A4 = PB05 - RPI_A5 = PB06 - RPI_A6 = PA04 - RPI_A7 = PB07 - RPI_A8 = PA06 - - PIN_DAC0 = PA02 - PIN_DAC1 = PA05 - - // FPO Analog RPIs - //FPC_A7 = FPC_D7 - //FPC_A8 = FPC_D8 - //FPC_A9 = FPC_D9 - //FPC_A11 = FPC_D11 - //FPC_A12 = FPC_D12 - //FPC_A13 = FPC_D13 - - // USB - PIN_USB_DM = PA24 - PIN_USB_DP = PA25 - PIN_USB_HOST_ENABLE = PA27 - - // BUTTON - BUTTON_1 = PC26 - BUTTON_2 = PC27 - BUTTON_3 = PC28 - WIO_KEY_A = PC26 - WIO_KEY_B = PC27 - WIO_KEY_C = PC28 - - // SWITCH - SWITCH_X = PD20 - SWITCH_Y = PD12 - SWITCH_Z = PD09 - SWITCH_B = PD08 - SWITCH_U = PD10 - - WIO_5S_UP = PD20 - WIO_5S_LEFT = PD12 - WIO_5S_RIGHT = PD09 - WIO_5S_DOWN = PD08 - WIO_5S_PRESS = PD10 - - // IRQ0 : RTL8720D - IRQ0 = PC20 - - // BUZZER_CTR - BUZZER_CTR = PD11 - WIO_BUZZER = PD11 - - // MIC_INPUT - MIC_INPUT = PC30 - WIO_MIC = PC30 - - // GCLK - GCLK0 = PB14 - GCLK1 = PB12 - GCLK2 = PB13 - - // Serial interfaces - // Serial1 - PIN_SERIAL1_RX = PB27 - PIN_SERIAL1_TX = PB26 - - // Serial2 : RTL8720D - PIN_SERIAL2_RX = PC23 - PIN_SERIAL2_TX = PC22 - - // Wire Interfaces - // I2C Wire2 - // I2C1 - PIN_WIRE_SDA = PA17 - PIN_WIRE_SCL = PA16 - SDA = PIN_WIRE_SDA - SCL = PIN_WIRE_SCL - - // I2C Wire1 - // I2C0 : LIS3DHTR and ATECC608 - PIN_WIRE1_SDA = PA13 - PIN_WIRE1_SCL = PA12 - - SDA1 = PIN_WIRE1_SDA - SCL1 = PIN_WIRE1_SCL - - PIN_GYROSCOPE_WIRE_SDA = PIN_WIRE1_SDA - PIN_GYROSCOPE_WIRE_SCL = PIN_WIRE1_SCL - GYROSCOPE_INT1 = PC21 - - WIO_LIS3DH_SDA = PIN_WIRE1_SDA - WIO_LIS3DH_SCL = PIN_WIRE1_SCL - WIO_LIS3DH_INT = PC21 - - // SPI - PIN_SPI_SDI = PB00 - PIN_SPI_SDO = PB02 - PIN_SPI_SCK = PB03 - PIN_SPI_SS = PB01 - - SS = PIN_SPI_SS - SDO = PIN_SPI_SDO - SDI = PIN_SPI_SDI - SCK = PIN_SPI_SCK - - // SPI1 RTL8720D_SPI - PIN_SPI1_SDI = PC24 - PIN_SPI1_SDO = PB24 - PIN_SPI1_SCK = PB25 - PIN_SPI1_SS = PC25 - - SS1 = PIN_SPI1_SS - SDO1 = PIN_SPI1_SDO - SDI1 = PIN_SPI1_SDI - SCK1 = PIN_SPI1_SCK - - // SPI2 SD_SPI - PIN_SPI2_SDI = PC18 - PIN_SPI2_SDO = PC16 - PIN_SPI2_SCK = PC17 - PIN_SPI2_SS = PC19 - - SS2 = PIN_SPI2_SS - SDO2 = PIN_SPI2_SDO - SDI2 = PIN_SPI2_SDI - SCK2 = PIN_SPI2_SCK - - // SPI3 LCD_SPI - PIN_SPI3_SDI = PB18 - PIN_SPI3_SDO = PB19 - PIN_SPI3_SCK = PB20 - PIN_SPI3_SS = PB21 - - SS3 = PIN_SPI3_SS - SDO3 = PIN_SPI3_SDO - SDI3 = PIN_SPI3_SDI - SCK3 = PIN_SPI3_SCK - - // Needed for SD library - SDCARD_SDI_PIN = PIN_SPI2_SDI - SDCARD_SDO_PIN = PIN_SPI2_SDO - SDCARD_SCK_PIN = PIN_SPI2_SCK - SDCARD_SS_PIN = PIN_SPI2_SS - SDCARD_DET_PIN = PD21 - - LCD_SDI_PIN = PIN_SPI3_SDI - LCD_SDO_PIN = PIN_SPI3_SDO - LCD_SCK_PIN = PIN_SPI3_SCK - LCD_SS_PIN = PIN_SPI3_SS - LCD_DC = PC06 - LCD_RESET = PC07 - LCD_BACKLIGHT = PC05 - - // 4 WIRE LCD TOUCH - LCD_XL = PC10 - LCD_YU = PC11 - LCD_XR = PC12 - LCD_YD = PC13 - - // Needed for RTL8720D - RTL8720D_SDI_PIN = PIN_SPI1_SDI - RTL8720D_SDO_PIN = PIN_SPI1_SDO - RTL8720D_SCK_PIN = PIN_SPI1_SCK - RTL8720D_SS_PIN = PIN_SPI1_SS - - //QSPI Pins - PIN_QSPI_IO0 = PA08 - PIN_QSPI_IO1 = PA09 - PIN_QSPI_IO2 = PA10 - PIN_QSPI_IO3 = PA11 - PIN_QSPI_SCK = PB10 - PIN_QSPI_CS = PB11 - - // I2S Interfaces - PIN_I2S_FS = PA20 - PIN_I2S_SCK = PB16 - PIN_I2S_SDO = PA22 - PIN_I2S_SDI = PA21 - - I2S_LRCLK = PA20 - I2S_BLCK = PB16 - I2S_SDOUT = PA22 - I2S_SDIN = PA21 - - // RTL8720D Interfaces - RTL8720D_CHIP_PU = PA18 - RTL8720D_GPIO0 = PA19 // SYNC - - // SWD - SWDCLK = PA30 - SWDIO = PA31 - SWO = PB30 - - // light sensor - WIO_LIGHT = PD01 - - // ir sensor - WIO_IR = PB31 - - // OUTPUT_CTR - OUTPUT_CTR_5V = PC14 - OUTPUT_CTR_3V3 = PC15 -) - -// USBCDC pins -const ( - USBCDC_DM_PIN = PIN_USB_DM - USBCDC_DP_PIN = PIN_USB_DP -) - -// UART1 pins -const ( - UART_TX_PIN = PIN_SERIAL1_TX - UART_RX_PIN = PIN_SERIAL1_RX -) - -// UART2 pins RTL8720D -const ( - UART2_TX_PIN = PIN_SERIAL2_TX - UART2_RX_PIN = PIN_SERIAL2_RX -) - -var ( - DefaultUART = UART1 - - UART1 = &sercomUSART2 - - // RTL8720D (tx: PC22, rx: PC23) - UART2 = &sercomUSART1 - - // RTL8720D (tx: PB24, rx: PC24) - UART3 = &sercomUSART0 - - // Right-hand grove port (tx: D0, rx: D1) - UART4 = &sercomUSART4 -) - -// I2C pins -const ( - SDA1_PIN = PA17 // SDA: SERCOM3/PAD[0] - SCL1_PIN = PA16 // SCL: SERCOM3/PAD[1] - - SDA0_PIN = PA13 // SDA: SERCOM4/PAD[0] - SCL0_PIN = PA12 // SCL: SERCOM4/PAD[1] - - SDA_PIN = SDA1_PIN - SCL_PIN = SCL1_PIN -) - -// I2C on the Wio Terminal -var ( - I2C0 = sercomI2CM4 - I2C1 = sercomI2CM3 -) - -// I2S pins -const ( - I2S_SCK_PIN = BCM18 - I2S_SDO_PIN = BCM21 - I2S_SDI_PIN = BCM20 - I2S_WS_PIN = BCM19 -) - -// SPI pins -const ( - SPI0_SCK_PIN = SCK // SCK: SERCOM5/PAD[1] - SPI0_SDO_PIN = SDO // SDO: SERCOM5/PAD[0] - SPI0_SDI_PIN = SDI // SDI: SERCOM5/PAD[2] - - // RTL8720D - SPI1_SCK_PIN = SCK1 // SCK: SERCOM0/PAD[1] - SPI1_SDO_PIN = SDO1 // SDO: SERCOM0/PAD[0] - SPI1_SDI_PIN = SDI1 // SDI: SERCOM0/PAD[2] - - // SD - SPI2_SCK_PIN = SCK2 // SCK: SERCOM6/PAD[1] - SPI2_SDO_PIN = SDO2 // SDO: SERCOM6/PAD[0] - SPI2_SDI_PIN = SDI2 // SDI: SERCOM6/PAD[2] - - // LCD - SPI3_SCK_PIN = SCK3 // SCK: SERCOM7/PAD[1] - SPI3_SDO_PIN = SDO3 // SDO: SERCOM7/PAD[3] - SPI3_SDI_PIN = SDI3 // SDI: SERCOM7/PAD[2] -) - -// SPI on the Wio Terminal -var ( - SPI0 = sercomSPIM5 - - // RTL8720D - SPI1 = sercomSPIM0 - - // SD - SPI2 = sercomSPIM6 - - // LCD - SPI3 = sercomSPIM7 -) - -// USB CDC identifiers -const ( - usb_STRING_PRODUCT = "Seeed Wio Terminal" - usb_STRING_MANUFACTURER = "Seeed" -) - -var ( - usb_VID uint16 = 0x2886 - usb_PID uint16 = 0x802D -) diff --git a/emb/machine/board_x9pro.go b/emb/machine/board_x9pro.go deleted file mode 100644 index 88468e9..0000000 --- a/emb/machine/board_x9pro.go +++ /dev/null @@ -1,30 +0,0 @@ -//go:build x9pro - -package machine - -// https://hackaday.io/project/144350-hacking-wearables-for-mental-health-and-more/details -const ( - LED Pin = 4 // HR LED pin - UART_TX_PIN Pin = NoPin - UART_RX_PIN Pin = NoPin - SCL_PIN Pin = NoPin - SDA_PIN Pin = NoPin - SPI0_SCK_PIN Pin = 18 - SPI0_SDI_PIN Pin = 19 - SPI0_SDO_PIN Pin = 20 -) - -// LCD pins. -const ( - OLED_CS Pin = 15 // chip select - OLED_RES Pin = 14 // reset pin - OLED_DC Pin = 13 // data/command - OLED_SCK Pin = 12 // SPI clock - OLED_SDO Pin = 11 // SPI SDO (chip-out, peripheral-in) - OLED_LED_POW Pin = 16 - OLED_IC_POW Pin = 17 -) - -const HasLowFrequencyCrystal = true - -var DefaultUART = UART0 diff --git a/emb/machine/board_xiao-ble.go b/emb/machine/board_xiao-ble.go deleted file mode 100644 index b4168d8..0000000 --- a/emb/machine/board_xiao-ble.go +++ /dev/null @@ -1,111 +0,0 @@ -//go:build xiao_ble - -// This file contains the pin mappings for the Seeed XIAO BLE nRF52840 [Sense] boards. -// -// Seeed XIAO BLE is an ultra-small size, ultra-low power Bluetooth development board based on the Nordic nRF52840. -// It features an onboard Bluetooth antenna, onboard battery charging chip, and 21*17.5mm thumb size, which makes it ideal for IoT projects. -// -// Seeed XIAO BLE nRF52840 Sense is a tiny Bluetooth LE development board designed for IoT and AI applications. -// It features an onboard antenna, 6 Dof IMU, microphone, all of which make it an ideal board to run AI using TinyML and TensorFlow Lite. -// -// SoftDevice (s140v7) is pre-flashed on this board already. -// See https://github.com/tinygo-org/bluetooth -// -// - https://www.seeedstudio.com/Seeed-XIAO-BLE-nRF52840-p-5201.html -// - https://www.seeedstudio.com/Seeed-XIAO-BLE-Sense-nRF52840-p-5253.html -// -// - https://wiki.seeedstudio.com/XIAO_BLE/ -// - https://github.com/Seeed-Studio/ArduinoCore-mbed/tree/master/variants/SEEED_XIAO_NRF52840_SENSE -package machine - -const HasLowFrequencyCrystal = true - -// Digital Pins -const ( - D0 Pin = P0_02 - D1 Pin = P0_03 - D2 Pin = P0_28 - D3 Pin = P0_29 - D4 Pin = P0_04 - D5 Pin = P0_05 - D6 Pin = P1_11 - D7 Pin = P1_12 - D8 Pin = P1_13 - D9 Pin = P1_14 - D10 Pin = P1_15 -) - -// Analog pins -const ( - A0 Pin = P0_02 - A1 Pin = P0_03 - A2 Pin = P0_28 - A3 Pin = P0_29 - A4 Pin = P0_04 - A5 Pin = P0_05 -) - -// Onboard LEDs -const ( - LED = LED_CHG - LED1 = LED_RED - LED2 = LED_GREEN - LED3 = LED_BLUE - LED_CHG = P0_17 - LED_RED = P0_26 - LED_GREEN = P0_30 - LED_BLUE = P0_06 -) - -// UART0 pins -const ( - UART_RX_PIN = P1_12 - UART_TX_PIN = P1_11 -) - -// I2C pins -const ( - // Defaults to internal - SDA_PIN = SDA1_PIN - SCL_PIN = SCL1_PIN - - // I2C0 (external) pins - SDA0_PIN = P0_04 - SCL0_PIN = P0_05 - - // I2C1 (internal) pins - SDA1_PIN = P0_07 - SCL1_PIN = P0_27 -) - -// SPI pins -const ( - SPI0_SCK_PIN = P1_13 - SPI0_SDO_PIN = P1_14 - SPI0_SDI_PIN = P1_15 -) - -// Peripherals -const ( - LSM_PWR = P1_08 // IMU (LSM6DS3TR) power - LSM_INT = P0_11 // IMU (LSM6DS3TR) interrupt - - MIC_PWR = P1_10 // Microphone (MSM261D3526H1CPM) power - MIC_CLK = P1_00 - MIC_DIN = P0_16 -) - -// USB CDC identifiers -const ( - usb_STRING_PRODUCT = "XIAO nRF52840 Sense" - usb_STRING_MANUFACTURER = "Seeed" -) - -var ( - usb_VID uint16 = 0x2886 - usb_PID uint16 = 0x8045 -) - -var ( - DefaultUART = UART0 -) diff --git a/emb/machine/board_xiao-esp32c3.go b/emb/machine/board_xiao-esp32c3.go deleted file mode 100644 index 5a2cf2e..0000000 --- a/emb/machine/board_xiao-esp32c3.go +++ /dev/null @@ -1,53 +0,0 @@ -//go:build xiao_esp32c3 - -// This file contains the pin mappings for the Seeed XIAO ESP32C3 boards. -// -// Seeed Studio XIAO ESP32C3 is an IoT mini development board based on -// the Espressif ESP32-C3 WiFi/Bluetooth dual-mode chip. -// -// - https://www.seeedstudio.com/Seeed-XIAO-ESP32C3-p-5431.html -// - https://wiki.seeedstudio.com/XIAO_ESP32C3_Getting_Started/ - -package machine - -// Digital Pins -const ( - D0 = GPIO2 - D1 = GPIO3 - D2 = GPIO4 - D3 = GPIO5 - D4 = GPIO6 - D5 = GPIO7 - D6 = GPIO21 - D7 = GPIO20 - D8 = GPIO8 - D9 = GPIO9 - D10 = GPIO10 -) - -// Analog pins -const ( - A0 = GPIO2 - A1 = GPIO3 - A2 = GPIO4 - A3 = GPIO5 -) - -// UART pins -const ( - UART_RX_PIN = GPIO20 - UART_TX_PIN = GPIO21 -) - -// I2C pins -const ( - SDA_PIN = GPIO6 - SCL_PIN = GPIO7 -) - -// SPI pins -const ( - SPI_SCK_PIN = GPIO8 - SPI_SDI_PIN = GPIO9 - SPI_SDO_PIN = GPIO10 -) diff --git a/emb/machine/board_xiao-rp2040.go b/emb/machine/board_xiao-rp2040.go deleted file mode 100644 index b010314..0000000 --- a/emb/machine/board_xiao-rp2040.go +++ /dev/null @@ -1,90 +0,0 @@ -//go:build xiao_rp2040 - -// This file contains the pin mappings for the Seeed XIAO RP2040 boards. -// -// XIAO RP2040 is a microcontroller using the Raspberry Pi RP2040 chip. -// -// - https://wiki.seeedstudio.com/XIAO-RP2040/ -package machine - -// Digital Pins -const ( - D0 Pin = GPIO26 - D1 Pin = GPIO27 - D2 Pin = GPIO28 - D3 Pin = GPIO29 - D4 Pin = GPIO6 - D5 Pin = GPIO7 - D6 Pin = GPIO0 - D7 Pin = GPIO1 - D8 Pin = GPIO2 - D9 Pin = GPIO4 - D10 Pin = GPIO3 -) - -// Analog pins -const ( - A0 Pin = D0 - A1 Pin = D1 - A2 Pin = D2 - A3 Pin = D3 -) - -// Onboard LEDs -const ( - NEOPIXEL = GPIO12 - WS2812 = GPIO12 - NEO_PWR = GPIO11 - NEOPIXEL_POWER = GPIO11 - - LED = GPIO17 - LED_RED = GPIO17 - LED_GREEN = GPIO16 - LED_BLUE = GPIO25 -) - -// I2C pins -const ( - I2C0_SDA_PIN Pin = D2 - I2C0_SCL_PIN Pin = D3 - - I2C1_SDA_PIN Pin = D4 - I2C1_SCL_PIN Pin = D5 -) - -// SPI pins -const ( - SPI0_SCK_PIN Pin = D8 - SPI0_SDO_PIN Pin = D10 - SPI0_SDI_PIN Pin = D9 - - SPI1_SCK_PIN Pin = NoPin - SPI1_SDO_PIN Pin = NoPin - SPI1_SDI_PIN Pin = NoPin -) - -// Onboard crystal oscillator frequency, in MHz. -const ( - xoscFreq = 12 // MHz -) - -// UART pins -const ( - UART0_TX_PIN = GPIO0 - UART0_RX_PIN = GPIO1 - UART_TX_PIN = UART0_TX_PIN - UART_RX_PIN = UART0_RX_PIN -) - -var DefaultUART = UART0 - -// USB CDC identifiers -const ( - usb_STRING_PRODUCT = "XIAO RP2040" - usb_STRING_MANUFACTURER = "Seeed" -) - -var ( - usb_VID uint16 = 0x2e8a - usb_PID uint16 = 0x000a -) diff --git a/emb/machine/board_xiao.go b/emb/machine/board_xiao.go deleted file mode 100644 index 5bbb34d..0000000 --- a/emb/machine/board_xiao.go +++ /dev/null @@ -1,103 +0,0 @@ -//go:build sam && atsamd21 && xiao - -package machine - -// used to reset into bootloader -const resetMagicValue = 0xf01669ef - -// GPIO Pins -const ( - D0 = PA02 // can be used for PWM or DAC - D1 = PA04 // PWM available - D2 = PA10 // PWM available - D3 = PA11 // PWM available - D4 = PA08 // can be used for PWM or I2C SDA - D5 = PA09 // can be used for PWM or I2C SCL - D6 = PB08 // can be used for PWM or UART1 TX - D7 = PB09 // can be used for PWM or UART1 RX - D8 = PA07 // can be used for PWM or SPI SCK - D9 = PA05 // can be used for PWM or SPI SDI - D10 = PA06 // can be used for PWM or SPI SDO -) - -// Analog pins -const ( - A0 = PA02 // ADC/AIN[0] - A1 = PA04 // ADC/AIN[4] - A2 = PA10 // ADC/AIN[18] - A3 = PA11 // ADC/AIN[19] - A4 = PA08 // ADC/AIN[16] - A5 = PA09 // ADC/AIN[17] - A6 = PB08 // ADC/AIN[2] - A7 = PB09 // ADC/AIN[3] - A8 = PA07 // ADC/AIN[7] - A9 = PA05 // ADC/AIN[6] - A10 = PA06 // ADC/AIN[5] -) - -const ( - LED = PA17 - LED_RXL = PA18 - LED_TXL = PA19 - LED2 = LED_RXL - LED3 = LED_TXL -) - -// USBCDC pins -const ( - USBCDC_DM_PIN = PA24 - USBCDC_DP_PIN = PA25 -) - -// UART1 pins -const ( - UART_TX_PIN = D6 - UART_RX_PIN = D7 -) - -// UART1 on the Xiao -var UART1 = &sercomUSART4 - -// I2C pins -const ( - SDA_PIN = PA08 // SDA: SERCOM2/PAD[0] - SCL_PIN = PA09 // SCL: SERCOM2/PAD[1] -) - -// I2C on the Xiao -var ( - I2C0 = sercomI2CM2 -) - -// SPI pins -const ( - SPI0_SCK_PIN = PA07 // SCK: SERCOM0/PAD[3] - SPI0_SDO_PIN = PA06 // SDO: SERCOM0/PAD[2] - SPI0_SDI_PIN = PA05 // SDI: SERCOM0/PAD[1] -) - -// SPI on the Xiao -var SPI0 = sercomSPIM0 - -// I2S pins -const ( - I2S_SCK_PIN = PA10 - I2S_SDO_PIN = PA08 - I2S_SDI_PIN = NoPin // TODO: figure out what this is on Xiao - I2S_WS_PIN = NoPin // TODO: figure out what this is on Xiao -) - -// USB CDC identifiers -const ( - usb_STRING_PRODUCT = "Seeed XIAO M0" - usb_STRING_MANUFACTURER = "Seeed" -) - -var ( - usb_VID uint16 = 0x2886 - usb_PID uint16 = 0x802F -) - -var ( - DefaultUART = UART1 -) diff --git a/emb/machine/buffer.go b/emb/machine/buffer.go deleted file mode 100644 index ff79157..0000000 --- a/emb/machine/buffer.go +++ /dev/null @@ -1,50 +0,0 @@ -package machine - -import ( - "github.com/goplus/lib/emb/runtime/volatile" -) - -// RingBuffer is ring buffer implementation inspired by post at -// https://www.embeddedrelated.com/showthread/comp.arch.embedded/77084-1.php -type RingBuffer struct { - rxbuffer [bufferSize]volatile.Register8 - head volatile.Register8 - tail volatile.Register8 -} - -// NewRingBuffer returns a new ring buffer. -func NewRingBuffer() *RingBuffer { - return &RingBuffer{} -} - -// Used returns how many bytes in buffer have been used. -func (rb *RingBuffer) Used() uint8 { - return uint8(rb.head.Get() - rb.tail.Get()) -} - -// Put stores a byte in the buffer. If the buffer is already -// full, the method will return false. -func (rb *RingBuffer) Put(val byte) bool { - if rb.Used() != bufferSize { - rb.head.Set(rb.head.Get() + 1) - rb.rxbuffer[rb.head.Get()%bufferSize].Set(val) - return true - } - return false -} - -// Get returns a byte from the buffer. If the buffer is empty, -// the method will return a false as the second value. -func (rb *RingBuffer) Get() (byte, bool) { - if rb.Used() != 0 { - rb.tail.Set(rb.tail.Get() + 1) - return rb.rxbuffer[rb.tail.Get()%bufferSize].Get(), true - } - return 0, false -} - -// Clear resets the head and tail pointer to zero. -func (rb *RingBuffer) Clear() { - rb.head.Set(0) - rb.tail.Set(0) -} diff --git a/emb/machine/buffer_atmega.go b/emb/machine/buffer_atmega.go deleted file mode 100644 index a321eae..0000000 --- a/emb/machine/buffer_atmega.go +++ /dev/null @@ -1,5 +0,0 @@ -//go:build atmega - -package machine - -const bufferSize = 32 diff --git a/emb/machine/buffer_generic.go b/emb/machine/buffer_generic.go deleted file mode 100644 index 0d82b44..0000000 --- a/emb/machine/buffer_generic.go +++ /dev/null @@ -1,5 +0,0 @@ -//go:build !atmega - -package machine - -const bufferSize = 128 diff --git a/emb/machine/deviceid.go b/emb/machine/deviceid.go deleted file mode 100644 index cb2e1d0..0000000 --- a/emb/machine/deviceid.go +++ /dev/null @@ -1,17 +0,0 @@ -//go:build rp2040 || nrf || sam - -package machine - -// DeviceID returns an identifier that is unique within -// a particular chipset. -// -// The identity is one burnt into the MCU itself, or the -// flash chip at time of manufacture. -// -// It's possible that two different vendors may allocate -// the same DeviceID, so callers should take this into -// account if needing to generate a globally unique id. -// -// The length of the hardware ID is vendor-specific, but -// 8 bytes (64 bits) and 16 bytes (128 bits) are common. -var _ = (func() []byte)(DeviceID) diff --git a/emb/machine/flash.go b/emb/machine/flash.go deleted file mode 100644 index c89c091..0000000 --- a/emb/machine/flash.go +++ /dev/null @@ -1,77 +0,0 @@ -//go:build nrf || nrf51 || nrf52 || nrf528xx || stm32f4 || stm32l4 || stm32wlx || atsamd21 || atsamd51 || atsame5x || rp2040 || rp2350 - -package machine - -import ( - "errors" - "io" - "unsafe" -) - -//go:extern __flash_data_start -var flashDataStart [0]byte - -//go:extern __flash_data_end -var flashDataEnd [0]byte - -// Return the start of the writable flash area, aligned on a page boundary. This -// is usually just after the program and static data. -func FlashDataStart() uintptr { - pagesize := uintptr(eraseBlockSize()) - return (uintptr(unsafe.Pointer(&flashDataStart)) + pagesize - 1) &^ (pagesize - 1) -} - -// Return the end of the writable flash area. Usually this is the address one -// past the end of the on-chip flash. -func FlashDataEnd() uintptr { - return uintptr(unsafe.Pointer(&flashDataEnd)) -} - -var ( - errFlashCannotErasePage = errors.New("cannot erase flash page") - errFlashInvalidWriteLength = errors.New("write flash data must align to correct number of bits") - errFlashNotAllowedWriteData = errors.New("not allowed to write flash data") - errFlashCannotWriteData = errors.New("cannot write flash data") - errFlashCannotReadPastEOF = errors.New("cannot read beyond end of flash data") - errFlashCannotWritePastEOF = errors.New("cannot write beyond end of flash data") - errFlashCannotErasePastEOF = errors.New("cannot erase beyond end of flash data") -) - -// BlockDevice is the raw device that is meant to store flash data. -type BlockDevice interface { - // ReadAt reads the given number of bytes from the block device. - io.ReaderAt - - // WriteAt writes the given number of bytes to the block device. - io.WriterAt - - // Size returns the number of bytes in this block device. - Size() int64 - - // WriteBlockSize returns the block size in which data can be written to - // memory. It can be used by a client to optimize writes, non-aligned writes - // should always work correctly. - WriteBlockSize() int64 - - // EraseBlockSize returns the smallest erasable area on this particular chip - // in bytes. This is used for the block size in EraseBlocks. - // It must be a power of two, and may be as small as 1. A typical size is 4096. - EraseBlockSize() int64 - - // EraseBlocks erases the given number of blocks. An implementation may - // transparently coalesce ranges of blocks into larger bundles if the chip - // supports this. The start and len parameters are in block numbers, use - // EraseBlockSize to map addresses to blocks. - EraseBlocks(start, len int64) error -} - -// pad data if needed so it is long enough for correct byte alignment on writes. -func flashPad(p []byte, writeBlockSize int) []byte { - overflow := len(p) % writeBlockSize - if overflow != 0 { - for i := 0; i < writeBlockSize-overflow; i++ { - p = append(p, 0xff) - } - } - return p -} diff --git a/emb/machine/i2c.go b/emb/machine/i2c.go deleted file mode 100644 index 3b1b4dd..0000000 --- a/emb/machine/i2c.go +++ /dev/null @@ -1,92 +0,0 @@ -//go:build !baremetal || atmega || nrf || sam || stm32 || fe310 || k210 || rp2040 || rp2350 || mimxrt1062 || (esp32c3 && !m5stamp_c3) || esp32 - -package machine - -import ( - "errors" -) - -// If you are getting a compile error on this line please check to see you've -// correctly implemented the methods on the I2C type. They must match -// the i2cController interface method signatures type to type perfectly. -// If not implementing the I2C type please remove your target from the build tags -// at the top of this file. -var _ interface { // 2 - Configure(config I2CConfig) error - Tx(addr uint16, w, r []byte) error - SetBaudRate(br uint32) error -} = (*I2C)(nil) - -// TWI_FREQ is the I2C bus speed. Normally either 100 kHz, or 400 kHz for high-speed bus. -// -// Deprecated: use 100 * machine.KHz or 400 * machine.KHz instead. -const ( - TWI_FREQ_100KHZ = 100000 - TWI_FREQ_400KHZ = 400000 -) - -var ( - errI2CWriteTimeout = errors.New("I2C timeout during write") - errI2CReadTimeout = errors.New("I2C timeout during read") - errI2CBusReadyTimeout = errors.New("I2C timeout on bus ready") - errI2CSignalStartTimeout = errors.New("I2C timeout on signal start") - errI2CSignalReadTimeout = errors.New("I2C timeout on signal read") - errI2CSignalStopTimeout = errors.New("I2C timeout on signal stop") - errI2CAckExpected = errors.New("I2C error: expected ACK not NACK") - errI2CBusError = errors.New("I2C bus error") - errI2COverflow = errors.New("I2C receive buffer overflow") - errI2COverread = errors.New("I2C transmit buffer overflow") - errI2CNotImplemented = errors.New("I2C operation not yet implemented") -) - -// I2CTargetEvent reflects events on the I2C bus -type I2CTargetEvent uint8 - -const ( - // I2CReceive indicates target has received a message from the controller. - I2CReceive I2CTargetEvent = iota - - // I2CRequest indicates the controller is expecting a message from the target. - I2CRequest - - // I2CFinish indicates the controller has ended the transaction. - // - // I2C controllers can chain multiple receive/request messages without - // relinquishing the bus by doing 'restarts'. I2CFinish indicates the - // bus has been relinquished by an I2C 'stop'. - I2CFinish -) - -// I2CMode determines if an I2C peripheral is in Controller or Target mode. -type I2CMode int - -const ( - // I2CModeController represents an I2C peripheral in controller mode. - I2CModeController I2CMode = iota - - // I2CModeTarget represents an I2C peripheral in target mode. - I2CModeTarget -) - -// WriteRegister transmits first the register and then the data to the -// peripheral device. -// -// Many I2C-compatible devices are organized in terms of registers. This method -// is a shortcut to easily write to such registers. Also, it only works for -// devices with 7-bit addresses, which is the vast majority. -func (i2c *I2C) WriteRegister(address uint8, register uint8, data []byte) error { - buf := make([]uint8, len(data)+1) - buf[0] = register - copy(buf[1:], data) - return i2c.Tx(uint16(address), buf, nil) -} - -// ReadRegister transmits the register, restarts the connection as a read -// operation, and reads the response. -// -// Many I2C-compatible devices are organized in terms of registers. This method -// is a shortcut to easily read such registers. Also, it only works for devices -// with 7-bit addresses, which is the vast majority. -func (i2c *I2C) ReadRegister(address uint8, register uint8, data []byte) error { - return i2c.Tx(uint16(address), []byte{register}, data) -} diff --git a/emb/machine/i2s.go b/emb/machine/i2s.go deleted file mode 100644 index 13dc80f..0000000 --- a/emb/machine/i2s.go +++ /dev/null @@ -1,80 +0,0 @@ -//go:build sam && atsamd21 - -// This is the definition for I2S bus functions. -// Actual implementations if available for any given hardware -// are to be found in its the board definition. -// -// For more info about I2S, see: https://en.wikipedia.org/wiki/I%C2%B2S -// - -package machine - -import "errors" - -// If you are getting a compile error on this line please check to see you've -// correctly implemented the methods on the I2S type. They must match -// the interface method signatures type to type perfectly. -// If not implementing the I2S type please remove your target from the build tags -// at the top of this file. -var _ interface { - SetSampleFrequency(freq uint32) error - ReadMono(b []uint16) (int, error) - ReadStereo(b []uint32) (int, error) - WriteMono(b []uint16) (int, error) - WriteStereo(b []uint32) (int, error) - Enable(enabled bool) -} = (*I2S)(nil) - -type I2SMode uint8 -type I2SStandard uint8 -type I2SClockSource uint8 -type I2SDataFormat uint8 - -const ( - I2SModeSource I2SMode = iota - I2SModeReceiver - I2SModePDM - I2SModeSourceReceiver -) - -const ( - I2StandardPhilips I2SStandard = iota - I2SStandardMSB - I2SStandardLSB -) - -const ( - I2SClockSourceInternal I2SClockSource = iota - I2SClockSourceExternal -) - -const ( - I2SDataFormatDefault I2SDataFormat = 0 - I2SDataFormat8bit = 8 - I2SDataFormat16bit = 16 - I2SDataFormat24bit = 24 - I2SDataFormat32bit = 32 -) - -var ( - ErrInvalidSampleFrequency = errors.New("i2s: invalid sample frequency") -) - -// All fields are optional and may not be required or used on a particular platform. -type I2SConfig struct { - // clock - SCK Pin - // word select - WS Pin - // data out - SDO Pin - // data in - SDI Pin - Mode I2SMode - Standard I2SStandard - ClockSource I2SClockSource - DataFormat I2SDataFormat - AudioFrequency uint32 - MainClockOutput bool - Stereo bool -} diff --git a/emb/machine/machine.go b/emb/machine/machine.go deleted file mode 100644 index def0395..0000000 --- a/emb/machine/machine.go +++ /dev/null @@ -1,64 +0,0 @@ -package machine - -import "errors" - -var ( - ErrTimeoutRNG = errors.New("machine: RNG Timeout") - ErrClockRNG = errors.New("machine: RNG Clock Error") - ErrSeedRNG = errors.New("machine: RNG Seed Error") - ErrInvalidInputPin = errors.New("machine: invalid input pin") - ErrInvalidOutputPin = errors.New("machine: invalid output pin") - ErrInvalidClockPin = errors.New("machine: invalid clock pin") - ErrInvalidDataPin = errors.New("machine: invalid data pin") - ErrNoPinChangeChannel = errors.New("machine: no channel available for pin interrupt") -) - -// Device is the running program's chip name, such as "ATSAMD51J19A" or -// "nrf52840". It is not the same as the CPU name. -// -// The constant is some hardcoded default value if the program does not target a -// particular chip but instead runs in WebAssembly for example. -const Device = deviceName - -// Generic constants. -const ( - KHz = 1000 - MHz = 1000_000 - GHz = 1000_000_000 -) - -// PinMode sets the direction and pull mode of the pin. For example, PinOutput -// sets the pin as an output and PinInputPullup sets the pin as an input with a -// pull-up. -type PinMode uint8 - -type PinConfig struct { - Mode PinMode -} - -// Pin is a single pin on a chip, which may be connected to other hardware -// devices. It can either be used directly as GPIO pin or it can be used in -// other peripherals like ADC, I2C, etc. -type Pin uint8 - -// NoPin explicitly indicates "not a pin". Use this pin if you want to leave one -// of the pins in a peripheral unconfigured (if supported by the hardware). -const NoPin = Pin(0xff) - -// High sets this GPIO pin to high, assuming it has been configured as an output -// pin. It is hardware dependent (and often undefined) what happens if you set a -// pin to high that is not configured as an output pin. -func (p Pin) High() { - p.Set(true) -} - -// Low sets this GPIO pin to low, assuming it has been configured as an output -// pin. It is hardware dependent (and often undefined) what happens if you set a -// pin to low that is not configured as an output pin. -func (p Pin) Low() { - p.Set(false) -} - -type ADC struct { - Pin Pin -} diff --git a/emb/machine/machine_atmega.go b/emb/machine/machine_atmega.go deleted file mode 100644 index 7a59e5e..0000000 --- a/emb/machine/machine_atmega.go +++ /dev/null @@ -1,340 +0,0 @@ -//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 -} diff --git a/emb/machine/machine_atmega1280.go b/emb/machine/machine_atmega1280.go deleted file mode 100644 index ad33dcf..0000000 --- a/emb/machine/machine_atmega1280.go +++ /dev/null @@ -1,937 +0,0 @@ -//go:build avr && atmega1280 - -package machine - -import ( - "device/avr" - "runtime/interrupt" - "runtime/volatile" -) - -const irq_USART0_RX = avr.IRQ_USART0_RX - -const ( - portA Pin = iota * 8 - portB - portC - portD - portE - portF - portG - portH - portJ - portK - portL -) - -const ( - PA0 = portA + 0 - PA1 = portA + 1 - PA2 = portA + 2 - PA3 = portA + 3 - PA4 = portA + 4 - PA5 = portA + 5 - PA6 = portA + 6 - PA7 = portA + 7 - PB0 = portB + 0 - PB1 = portB + 1 - PB2 = portB + 2 - PB3 = portB + 3 - PB4 = portB + 4 // peripherals: Timer2 channel A - PB5 = portB + 5 // peripherals: Timer1 channel A - PB6 = portB + 6 // peripherals: Timer1 channel B - PB7 = portB + 7 // peripherals: Timer0 channel A - PC0 = portC + 0 - PC1 = portC + 1 - PC2 = portC + 2 - PC3 = portC + 3 - PC4 = portC + 4 - PC5 = portC + 5 - PC6 = portC + 6 - PC7 = portC + 7 - PD0 = portD + 0 - PD1 = portD + 1 - PD2 = portD + 2 - PD3 = portD + 3 - PD7 = portD + 7 - PE0 = portE + 0 - PE1 = portE + 1 - PE3 = portE + 3 // peripherals: Timer3 channel A - PE4 = portE + 4 // peripherals: Timer3 channel B - PE5 = portE + 5 // peripherals: Timer3 channel C - PE6 = portE + 6 - PF0 = portF + 0 - PF1 = portF + 1 - PF2 = portF + 2 - PF3 = portF + 3 - PF4 = portF + 4 - PF5 = portF + 5 - PF6 = portF + 6 - PF7 = portF + 7 - PG0 = portG + 0 - PG1 = portG + 1 - PG2 = portG + 2 - PG5 = portG + 5 // peripherals: Timer0 channel B - PH0 = portH + 0 - PH1 = portH + 1 - PH3 = portH + 3 // peripherals: Timer4 channel A - PH4 = portH + 4 // peripherals: Timer4 channel B - PH5 = portH + 5 // peripherals: Timer4 channel C - PH6 = portH + 6 // peripherals: Timer0 channel B - PJ0 = portJ + 0 - PJ1 = portJ + 1 - PK0 = portK + 0 - PK1 = portK + 1 - PK2 = portK + 2 - PK3 = portK + 3 - PK4 = portK + 4 - PK5 = portK + 5 - PK6 = portK + 6 - PK7 = portK + 7 - PL0 = portL + 0 - PL1 = portL + 1 - PL2 = portL + 2 - PL3 = portL + 3 // peripherals: Timer5 channel A - PL4 = portL + 4 // peripherals: Timer5 channel B - PL5 = portL + 5 // peripherals: Timer5 channel C - PL6 = portL + 6 - PL7 = portL + 7 -) - -// getPortMask returns the PORTx register and mask for the pin. -func (p Pin) getPortMask() (*volatile.Register8, uint8) { - switch { - case p >= PA0 && p <= PA7: - return avr.PORTA, 1 << uint8(p-portA) - case p >= PB0 && p <= PB7: - return avr.PORTB, 1 << uint8(p-portB) - case p >= PC0 && p <= PC7: - return avr.PORTC, 1 << uint8(p-portC) - case p >= PD0 && p <= PD7: - return avr.PORTD, 1 << uint8(p-portD) - case p >= PE0 && p <= PE6: - return avr.PORTE, 1 << uint8(p-portE) - case p >= PF0 && p <= PF7: - return avr.PORTF, 1 << uint8(p-portF) - case p >= PG0 && p <= PG5: - return avr.PORTG, 1 << uint8(p-portG) - case p >= PH0 && p <= PH6: - return avr.PORTH, 1 << uint8(p-portH) - case p >= PJ0 && p <= PJ1: - return avr.PORTJ, 1 << uint8(p-portJ) - case p >= PK0 && p <= PK7: - return avr.PORTK, 1 << uint8(p-portK) - case p >= PL0 && p <= PL7: - return avr.PORTL, 1 << uint8(p-portL) - default: - return avr.PORTA, 255 - } -} - -// PWM is one PWM peripheral, which consists of a counter and two output -// channels (that can be connected to two fixed pins). You can set the frequency -// using SetPeriod, but only for all the channels in this PWM peripheral at -// once. -type PWM struct { - num uint8 -} - -var ( - Timer0 = PWM{0} // 8 bit timer for PB7 and PG5 - Timer1 = PWM{1} // 16 bit timer for PB5 and PB6 - Timer2 = PWM{2} // 8 bit timer for PB4 and PH6 - Timer3 = PWM{3} // 16 bit timer for PE3, PE4 and PE5 - Timer4 = PWM{4} // 16 bit timer for PH3, PH4 and PH5 - Timer5 = PWM{5} // 16 bit timer for PL3, PL4 and PL5 -) - -// Configure enables and configures this PWM. -// -// For the two 8 bit timers, there is only a limited number of periods -// available, namely the CPU frequency divided by 256 and again divided by 1, 8, -// 64, 256, or 1024. For a MCU running at 16MHz, this would be a period of 16µs, -// 128µs, 1024µs, 4096µs, or 16384µs. -func (pwm PWM) Configure(config PWMConfig) error { - - switch pwm.num { - case 0, 2: // 8-bit timers (Timer/counter 0 and Timer/counter 2) - // Calculate the timer prescaler. - // While we could configure a flexible top, that would sacrifice one of - // the PWM output compare registers and thus a PWM channel. I've chosen - // to instead limit this timer to a fixed number of frequencies. - var prescaler uint8 - switch config.Period { - case 0, (uint64(1e9) * 256 * 1) / uint64(CPUFrequency()): - prescaler = 1 - case (uint64(1e9) * 256 * 8) / uint64(CPUFrequency()): - prescaler = 2 - case (uint64(1e9) * 256 * 64) / uint64(CPUFrequency()): - prescaler = 3 - case (uint64(1e9) * 256 * 256) / uint64(CPUFrequency()): - prescaler = 4 - case (uint64(1e9) * 256 * 1024) / uint64(CPUFrequency()): - prescaler = 5 - default: - return ErrPWMPeriodTooLong - } - - if pwm.num == 0 { - avr.TCCR0B.Set(prescaler) - // Set the PWM mode to fast PWM (mode = 3). - avr.TCCR0A.Set(avr.TCCR0A_WGM00 | avr.TCCR0A_WGM01) - // monotonic timer is using the same time as PWM:0 - // we must adjust internal settings of monotonic timer when PWM:0 settings changed - adjustMonotonicTimer() - } else { - avr.TCCR2B.Set(prescaler) - // Set the PWM mode to fast PWM (mode = 3). - avr.TCCR2A.Set(avr.TCCR2A_WGM20 | avr.TCCR2A_WGM21) - } - case 1, 3, 4, 5: - // The top value is the number of PWM ticks a PWM period takes. It is - // initially picked assuming an unlimited counter top and no PWM - // prescaler. - var top uint64 - if config.Period == 0 { - // Use a top appropriate for LEDs. Picking a relatively low period - // here (0xff) for consistency with the other timers. - top = 0xff - } else { - // The formula below calculates the following formula, optimized: - // top = period * (CPUFrequency() / 1e9) - // By dividing the CPU frequency first (an operation that is easily - // optimized away) the period has less chance of overflowing. - top = config.Period * (uint64(CPUFrequency()) / 1000000) / 1000 - } - - // The ideal PWM period may be larger than would fit in the PWM counter, - // which is 16 bits (see maxTop). Therefore, try to make the PWM clock - // speed lower with a prescaler to make the top value fit the maximum - // top value. - - const maxTop = 0x10000 - var prescalingTop uint8 - switch { - case top <= maxTop: - prescalingTop = 3<<3 | 1 // no prescaling - case top/8 <= maxTop: - prescalingTop = 3<<3 | 2 // divide by 8 - top /= 8 - case top/64 <= maxTop: - prescalingTop = 3<<3 | 3 // divide by 64 - top /= 64 - case top/256 <= maxTop: - prescalingTop = 3<<3 | 4 // divide by 256 - top /= 256 - case top/1024 <= maxTop: - prescalingTop = 3<<3 | 5 // divide by 1024 - top /= 1024 - default: - return ErrPWMPeriodTooLong - } - - // A top of 0x10000 is at 100% duty cycle. Subtract one because the - // counter counts from 0, not 1 (avoiding an off-by-one). - top -= 1 - - switch pwm.num { - case 1: - avr.TCCR1A.Set(avr.TCCR1A_WGM11) - avr.TCCR1B.Set(prescalingTop) - avr.ICR1H.Set(uint8(top >> 8)) - avr.ICR1L.Set(uint8(top)) - case 3: - avr.TCCR3A.Set(avr.TCCR3A_WGM31) - avr.TCCR3B.Set(prescalingTop) - avr.ICR3H.Set(uint8(top >> 8)) - avr.ICR3L.Set(uint8(top)) - case 4: - avr.TCCR4A.Set(avr.TCCR4A_WGM41) - avr.TCCR4B.Set(prescalingTop) - avr.ICR4H.Set(uint8(top >> 8)) - avr.ICR4L.Set(uint8(top)) - case 5: - avr.TCCR5A.Set(avr.TCCR5A_WGM51) - avr.TCCR5B.Set(prescalingTop) - avr.ICR5H.Set(uint8(top >> 8)) - avr.ICR5L.Set(uint8(top)) - } - } - return nil -} - -// SetPeriod updates the period of this PWM peripheral. -// To set a particular frequency, use the following formula: -// -// period = 1e9 / frequency -// -// If you use a period of 0, a period that works well for LEDs will be picked. -// -// SetPeriod will not change the prescaler, but also won't change the current -// value in any of the channels. This means that you may need to update the -// value for the particular channel. -// -// Note that you cannot pick any arbitrary period after the PWM peripheral has -// been configured. If you want to switch between frequencies, pick the lowest -// frequency (longest period) once when calling Configure and adjust the -// frequency here as needed. -func (pwm PWM) SetPeriod(period uint64) error { - if pwm.num == 0 || pwm.num == 2 { - return ErrPWMPeriodTooLong // TODO better error message - } - - // The top value is the number of PWM ticks a PWM period takes. It is - // initially picked assuming an unlimited counter top and no PWM - // prescaler. - var top uint64 - if period == 0 { - // Use a top appropriate for LEDs. Picking a relatively low period - // here (0xff) for consistency with the other timers. - top = 0xff - } else { - // The formula below calculates the following formula, optimized: - // top = period * (CPUFrequency() / 1e9) - // By dividing the CPU frequency first (an operation that is easily - // optimized away) the period has less chance of overflowing. - top = period * (uint64(CPUFrequency()) / 1000000) / 1000 - } - - var prescaler uint8 - - switch pwm.num { - case 1: - prescaler = avr.TCCR1B.Get() & 0x7 - case 3: - prescaler = avr.TCCR3B.Get() & 0x7 - case 4: - prescaler = avr.TCCR4B.Get() & 0x7 - case 5: - prescaler = avr.TCCR5B.Get() & 0x7 - } - - switch prescaler { - case 1: - top /= 1 - case 2: - top /= 8 - case 3: - top /= 64 - case 4: - top /= 256 - case 5: - top /= 1024 - } - - // A top of 0x10000 is at 100% duty cycle. Subtract one because the counter - // counts from 0, not 1 (avoiding an off-by-one). - top -= 1 - - if top > 0xffff { - return ErrPWMPeriodTooLong - } - - switch pwm.num { - case 1: - // Warning: this change is not atomic! - avr.ICR1H.Set(uint8(top >> 8)) - avr.ICR1L.Set(uint8(top)) - - // ... and because of that, set the counter back to zero to avoid most of - // the effects of this non-atomicity. - avr.TCNT1H.Set(0) - avr.TCNT1L.Set(0) - case 3: - // Warning: this change is not atomic! - avr.ICR3H.Set(uint8(top >> 8)) - avr.ICR3L.Set(uint8(top)) - - // ... and because of that, set the counter back to zero to avoid most of - // the effects of this non-atomicity. - avr.TCNT3H.Set(0) - avr.TCNT3L.Set(0) - case 4: - // Warning: this change is not atomic! - avr.ICR4H.Set(uint8(top >> 8)) - avr.ICR4L.Set(uint8(top)) - - // ... and because of that, set the counter back to zero to avoid most of - // the effects of this non-atomicity. - avr.TCNT4H.Set(0) - avr.TCNT4L.Set(0) - case 5: - // Warning: this change is not atomic! - avr.ICR5H.Set(uint8(top >> 8)) - avr.ICR5L.Set(uint8(top)) - - // ... and because of that, set the counter back to zero to avoid most of - // the effects of this non-atomicity. - avr.TCNT5H.Set(0) - avr.TCNT5L.Set(0) - } - - return nil -} - -// Top returns the current counter top, for use in duty cycle calculation. It -// will only change with a call to Configure or SetPeriod, otherwise it is -// constant. -// -// The value returned here is hardware dependent. In general, it's best to treat -// it as an opaque value that can be divided by some number and passed to Set -// (see Set documentation for more information). -func (pwm PWM) Top() uint32 { - switch pwm.num { - case 1: - // Timer 1 has a configurable top value. - low := avr.ICR1L.Get() - high := avr.ICR1H.Get() - return uint32(high)<<8 | uint32(low) + 1 - case 3: - // Timer 3 has a configurable top value. - low := avr.ICR3L.Get() - high := avr.ICR3H.Get() - return uint32(high)<<8 | uint32(low) + 1 - case 4: - // Timer 4 has a configurable top value. - low := avr.ICR4L.Get() - high := avr.ICR4H.Get() - return uint32(high)<<8 | uint32(low) + 1 - case 5: - // Timer 5 has a configurable top value. - low := avr.ICR5L.Get() - high := avr.ICR5H.Get() - return uint32(high)<<8 | uint32(low) + 1 - } - - // Other timers go from 0 to 0xff (0x100 or 256 in total). - return 256 -} - -// Counter returns the current counter value of the timer in this PWM -// peripheral. It may be useful for debugging. -func (pwm PWM) Counter() uint32 { - switch pwm.num { - case 0: - return uint32(avr.TCNT0.Get()) - case 1: - mask := interrupt.Disable() - low := avr.TCNT1L.Get() - high := avr.TCNT1H.Get() - interrupt.Restore(mask) - return uint32(high)<<8 | uint32(low) - case 2: - return uint32(avr.TCNT2.Get()) - case 3: - mask := interrupt.Disable() - low := avr.TCNT3L.Get() - high := avr.TCNT3H.Get() - interrupt.Restore(mask) - return uint32(high)<<8 | uint32(low) - case 4: - mask := interrupt.Disable() - low := avr.TCNT4L.Get() - high := avr.TCNT4H.Get() - interrupt.Restore(mask) - return uint32(high)<<8 | uint32(low) - case 5: - mask := interrupt.Disable() - low := avr.TCNT5L.Get() - high := avr.TCNT5H.Get() - interrupt.Restore(mask) - return uint32(high)<<8 | uint32(low) - } - - // Unknown PWM. - return 0 -} - -// Period returns the used PWM period in nanoseconds. It might deviate slightly -// from the configured period due to rounding. -func (pwm PWM) Period() uint64 { - var prescaler uint8 - switch pwm.num { - case 0: - prescaler = avr.TCCR0B.Get() & 0x7 - case 1: - prescaler = avr.TCCR1B.Get() & 0x7 - case 2: - prescaler = avr.TCCR2B.Get() & 0x7 - case 3: - prescaler = avr.TCCR3B.Get() & 0x7 - case 4: - prescaler = avr.TCCR4B.Get() & 0x7 - case 5: - prescaler = avr.TCCR5B.Get() & 0x7 - } - top := uint64(pwm.Top()) - switch prescaler { - case 1: // prescaler 1 - return 1 * top * 1000 / uint64(CPUFrequency()/1e6) - case 2: // prescaler 8 - return 8 * top * 1000 / uint64(CPUFrequency()/1e6) - case 3: // prescaler 64 - return 64 * top * 1000 / uint64(CPUFrequency()/1e6) - case 4: // prescaler 256 - return 256 * top * 1000 / uint64(CPUFrequency()/1e6) - case 5: // prescaler 1024 - return 1024 * top * 1000 / uint64(CPUFrequency()/1e6) - default: // unknown clock source - return 0 - } -} - -// Channel returns a PWM channel for the given pin. -func (pwm PWM) Channel(pin Pin) (uint8, error) { - pin.Configure(PinConfig{Mode: PinOutput}) - pin.Low() - switch pwm.num { - case 0: - switch pin { - case PB7: // channel A - avr.TCCR0A.SetBits(avr.TCCR0A_COM0A1) - return 0, nil - case PG5: // channel B - avr.TCCR0A.SetBits(avr.TCCR0A_COM0B1) - return 1, nil - } - case 1: - switch pin { - case PB5: // channel A - avr.TCCR1A.SetBits(avr.TCCR1A_COM1A1) - return 0, nil - case PB6: // channel B - avr.TCCR1A.SetBits(avr.TCCR1A_COM1B1) - return 1, nil - } - case 2: - switch pin { - case PB4: // channel A - avr.TCCR2A.SetBits(avr.TCCR2A_COM2A1) - return 0, nil - case PH6: // channel B - avr.TCCR2A.SetBits(avr.TCCR2A_COM2B1) - return 1, nil - } - case 3: - switch pin { - case PE3: // channel A - avr.TCCR3A.SetBits(avr.TCCR3A_COM3A1) - return 0, nil - case PE4: //channel B - avr.TCCR3A.SetBits(avr.TCCR3A_COM3B1) - return 1, nil - case PE5: //channel C - avr.TCCR3A.SetBits(avr.TCCR3A_COM3C1) - return 2, nil - } - case 4: - switch pin { - case PH3: // channel A - avr.TCCR4A.SetBits(avr.TCCR4A_COM4A1) - return 0, nil - case PH4: //channel B - avr.TCCR4A.SetBits(avr.TCCR4A_COM4B1) - return 1, nil - case PH5: //channel C - avr.TCCR4A.SetBits(avr.TCCR4A_COM4C1) - return 2, nil - } - case 5: - switch pin { - case PL3: // channel A - avr.TCCR5A.SetBits(avr.TCCR5A_COM5A1) - return 0, nil - case PL4: //channel B - avr.TCCR5A.SetBits(avr.TCCR5A_COM5B1) - return 1, nil - case PL5: //channel C - avr.TCCR5A.SetBits(avr.TCCR5A_COM5C1) - return 2, nil - } - } - return 0, ErrInvalidOutputPin -} - -// SetInverting sets whether to invert the output of this channel. -// Without inverting, a 25% duty cycle would mean the output is high for 25% of -// the time and low for the rest. Inverting flips the output as if a NOT gate -// was placed at the output, meaning that the output would be 25% low and 75% -// high with a duty cycle of 25%. -// -// Note: the invert state may not be applied on the AVR until the next call to -// ch.Set(). -func (pwm PWM) SetInverting(channel uint8, inverting bool) { - switch pwm.num { - case 0: - switch channel { - case 0: // channel A, PB7 - if inverting { - avr.PORTB.SetBits(1 << 7) // PB7 high - avr.TCCR0A.SetBits(avr.TCCR0A_COM0A0) - } else { - avr.PORTB.ClearBits(1 << 7) // PB7 low - avr.TCCR0A.ClearBits(avr.TCCR0A_COM0A0) - } - case 1: // channel B, PG5 - if inverting { - avr.PORTG.SetBits(1 << 5) // PG5 high - avr.TCCR0A.SetBits(avr.TCCR0A_COM0B0) - } else { - avr.PORTG.ClearBits(1 << 5) // PG5 low - avr.TCCR0A.ClearBits(avr.TCCR0A_COM0B0) - } - } - case 1: - // Note: the COM1A0/COM1B0 bit is not set with the configuration below. - // It will be set the following call to Set(), however. - switch channel { - case 0: // channel A, PB5 - if inverting { - avr.PORTB.SetBits(1 << 5) // PB5 high - } else { - avr.PORTB.ClearBits(1 << 5) // PB5 low - } - case 1: // channel B, PB6 - if inverting { - avr.PORTB.SetBits(1 << 6) // PB6 high - } else { - avr.PORTB.ClearBits(1 << 6) // PB6 low - } - } - case 2: - switch channel { - case 0: // channel A, PB4 - if inverting { - avr.PORTB.SetBits(1 << 4) // PB4 high - avr.TCCR2A.SetBits(avr.TCCR2A_COM2A0) - } else { - avr.PORTB.ClearBits(1 << 4) // PB4 low - avr.TCCR2A.ClearBits(avr.TCCR2A_COM2A0) - } - case 1: // channel B, PH6 - if inverting { - avr.PORTH.SetBits(1 << 6) // PH6 high - avr.TCCR2A.SetBits(avr.TCCR2A_COM2B0) - } else { - avr.PORTH.ClearBits(1 << 6) // PH6 low - avr.TCCR2A.ClearBits(avr.TCCR2A_COM2B0) - } - } - case 3: - // Note: the COM3A0/COM3B0 bit is not set with the configuration below. - // It will be set the following call to Set(), however. - switch channel { - case 0: // channel A, PE3 - if inverting { - avr.PORTE.SetBits(1 << 3) // PE3 high - } else { - avr.PORTE.ClearBits(1 << 3) // PE3 low - } - case 1: // channel B, PE4 - if inverting { - avr.PORTE.SetBits(1 << 4) // PE4 high - } else { - avr.PORTE.ClearBits(1 << 4) // PE4 low - } - case 2: // channel C, PE5 - if inverting { - avr.PORTE.SetBits(1 << 5) // PE4 high - } else { - avr.PORTE.ClearBits(1 << 5) // PE4 low - } - } - case 4: - // Note: the COM3A0/COM3B0 bit is not set with the configuration below. - // It will be set the following call to Set(), however. - switch channel { - case 0: // channel A, PH3 - if inverting { - avr.PORTH.SetBits(1 << 3) // PH3 high - } else { - avr.PORTH.ClearBits(1 << 3) // PH3 low - } - case 1: // channel B, PH4 - if inverting { - avr.PORTH.SetBits(1 << 4) // PH4 high - } else { - avr.PORTH.ClearBits(1 << 4) // PH4 low - } - case 2: // channel C, PH5 - if inverting { - avr.PORTH.SetBits(1 << 5) // PH4 high - } else { - avr.PORTH.ClearBits(1 << 5) // PH4 low - } - } - case 5: - // Note: the COM3A0/COM3B0 bit is not set with the configuration below. - // It will be set the following call to Set(), however. - switch channel { - case 0: // channel A, PL3 - if inverting { - avr.PORTL.SetBits(1 << 3) // PL3 high - } else { - avr.PORTL.ClearBits(1 << 3) // PL3 low - } - case 1: // channel B, PL4 - if inverting { - avr.PORTL.SetBits(1 << 4) // PL4 high - } else { - avr.PORTL.ClearBits(1 << 4) // PL4 low - } - case 2: // channel C, PH5 - if inverting { - avr.PORTL.SetBits(1 << 5) // PL4 high - } else { - avr.PORTL.ClearBits(1 << 5) // PL4 low - } - } - } -} - -// Set updates the channel value. This is used to control the channel duty -// cycle, in other words the fraction of time the channel output is high (or low -// when inverted). For example, to set it to a 25% duty cycle, use: -// -// pwm.Set(channel, pwm.Top() / 4) -// -// pwm.Set(channel, 0) will set the output to low and pwm.Set(channel, -// pwm.Top()) will set the output to high, assuming the output isn't inverted. -func (pwm PWM) Set(channel uint8, value uint32) { - switch pwm.num { - case 0: - value := uint16(value) - switch channel { - case 0: // channel A - if value == 0 { - avr.TCCR0A.ClearBits(avr.TCCR0A_COM0A1) - } else { - avr.OCR0A.Set(uint8(value - 1)) - avr.TCCR0A.SetBits(avr.TCCR0A_COM0A1) - } - case 1: // channel B - if value == 0 { - avr.TCCR0A.ClearBits(avr.TCCR0A_COM0B1) - } else { - avr.OCR0B.Set(uint8(value) - 1) - avr.TCCR0A.SetBits(avr.TCCR0A_COM0B1) - } - } - // monotonic timer is using the same time as PWM:0 - // we must adjust internal settings of monotonic timer when PWM:0 settings changed - adjustMonotonicTimer() - case 1: - mask := interrupt.Disable() - switch channel { - case 0: // channel A, PB5 - if value == 0 { - avr.TCCR1A.ClearBits(avr.TCCR1A_COM1A1 | avr.TCCR1A_COM1A0) - } else { - value := uint16(value) - 1 // yes, this is safe (it relies on underflow) - avr.OCR1AH.Set(uint8(value >> 8)) - avr.OCR1AL.Set(uint8(value)) - if avr.PORTB.HasBits(1 << 5) { // is PB1 high? - // Yes, set the inverting bit. - avr.TCCR1A.SetBits(avr.TCCR1A_COM1A1 | avr.TCCR1A_COM1A0) - } else { - // No, output is non-inverting. - avr.TCCR1A.SetBits(avr.TCCR1A_COM1A1) - } - } - case 1: // channel B, PB6 - if value == 0 { - avr.TCCR1A.ClearBits(avr.TCCR1A_COM1B1 | avr.TCCR1A_COM1B0) - } else { - value := uint16(value) - 1 // yes, this is safe (it relies on underflow) - avr.OCR1BH.Set(uint8(value >> 8)) - avr.OCR1BL.Set(uint8(value)) - if avr.PORTB.HasBits(1 << 6) { // is PB6 high? - // Yes, set the inverting bit. - avr.TCCR1A.SetBits(avr.TCCR1A_COM1B1 | avr.TCCR1A_COM1B0) - } else { - // No, output is non-inverting. - avr.TCCR1A.SetBits(avr.TCCR1A_COM1B1) - } - } - } - interrupt.Restore(mask) - case 2: - value := uint16(value) - switch channel { - case 0: // channel A - if value == 0 { - avr.TCCR2A.ClearBits(avr.TCCR2A_COM2A1) - } else { - avr.OCR2A.Set(uint8(value - 1)) - avr.TCCR2A.SetBits(avr.TCCR2A_COM2A1) - } - case 1: // channel B - if value == 0 { - avr.TCCR2A.ClearBits(avr.TCCR2A_COM2B1) - } else { - avr.OCR2B.Set(uint8(value - 1)) - avr.TCCR2A.SetBits(avr.TCCR2A_COM2B1) - } - } - case 3: - mask := interrupt.Disable() - switch channel { - case 0: // channel A, PE3 - if value == 0 { - avr.TCCR3A.ClearBits(avr.TCCR3A_COM3A1 | avr.TCCR3A_COM3A0) - } else { - value := uint16(value) - 1 // yes, this is safe (it relies on underflow) - avr.OCR3AH.Set(uint8(value >> 8)) - avr.OCR3AL.Set(uint8(value)) - if avr.PORTE.HasBits(1 << 3) { // is PE3 high? - // Yes, set the inverting bit. - avr.TCCR3A.SetBits(avr.TCCR3A_COM3A1 | avr.TCCR3A_COM3A0) - } else { - // No, output is non-inverting. - avr.TCCR3A.SetBits(avr.TCCR3A_COM3A1) - } - } - case 1: // channel B, PE4 - if value == 0 { - avr.TCCR3A.ClearBits(avr.TCCR3A_COM3B1 | avr.TCCR3A_COM3B0) - } else { - value := uint16(value) - 1 // yes, this is safe (it relies on underflow) - avr.OCR3BH.Set(uint8(value >> 8)) - avr.OCR3BL.Set(uint8(value)) - if avr.PORTE.HasBits(1 << 4) { // is PE4 high? - // Yes, set the inverting bit. - avr.TCCR3A.SetBits(avr.TCCR3A_COM3B1 | avr.TCCR3A_COM3B0) - } else { - // No, output is non-inverting. - avr.TCCR3A.SetBits(avr.TCCR3A_COM3B1) - } - } - case 2: // channel C, PE5 - if value == 0 { - avr.TCCR3A.ClearBits(avr.TCCR3A_COM3C1 | avr.TCCR3A_COM3C0) - } else { - value := uint16(value) - 1 // yes, this is safe (it relies on underflow) - avr.OCR3CH.Set(uint8(value >> 8)) - avr.OCR3CL.Set(uint8(value)) - if avr.PORTE.HasBits(1 << 5) { // is PE5 high? - // Yes, set the inverting bit. - avr.TCCR3A.SetBits(avr.TCCR3A_COM3C1 | avr.TCCR3A_COM3C0) - } else { - // No, output is non-inverting. - avr.TCCR3A.SetBits(avr.TCCR3A_COM3C1) - } - } - } - interrupt.Restore(mask) - case 4: - mask := interrupt.Disable() - switch channel { - case 0: // channel A, PH3 - if value == 0 { - avr.TCCR4A.ClearBits(avr.TCCR4A_COM4A1 | avr.TCCR4A_COM4A0) - } else { - value := uint16(value) - 1 // yes, this is safe (it relies on underflow) - avr.OCR4AH.Set(uint8(value >> 8)) - avr.OCR4AL.Set(uint8(value)) - if avr.PORTH.HasBits(1 << 3) { // is PH3 high? - // Yes, set the inverting bit. - avr.TCCR4A.SetBits(avr.TCCR4A_COM4A1 | avr.TCCR4A_COM4A0) - } else { - // No, output is non-inverting. - avr.TCCR4A.SetBits(avr.TCCR4A_COM4A1) - } - } - case 1: // channel B, PH4 - if value == 0 { - avr.TCCR4A.ClearBits(avr.TCCR4A_COM4B1 | avr.TCCR4A_COM4B0) - } else { - value := uint16(value) - 1 // yes, this is safe (it relies on underflow) - avr.OCR4BH.Set(uint8(value >> 8)) - avr.OCR4BL.Set(uint8(value)) - if avr.PORTH.HasBits(1 << 4) { // is PH4 high? - // Yes, set the inverting bit. - avr.TCCR4A.SetBits(avr.TCCR4A_COM4B1 | avr.TCCR4A_COM4B0) - } else { - // No, output is non-inverting. - avr.TCCR4A.SetBits(avr.TCCR4A_COM4B1) - } - } - case 2: // channel C, PH5 - if value == 0 { - avr.TCCR4A.ClearBits(avr.TCCR4A_COM4C1 | avr.TCCR4A_COM4C0) - } else { - value := uint16(value) - 1 // yes, this is safe (it relies on underflow) - avr.OCR4CH.Set(uint8(value >> 8)) - avr.OCR4CL.Set(uint8(value)) - if avr.PORTH.HasBits(1 << 5) { // is PH5 high? - // Yes, set the inverting bit. - avr.TCCR4A.SetBits(avr.TCCR4A_COM4C1 | avr.TCCR4A_COM4C0) - } else { - // No, output is non-inverting. - avr.TCCR4A.SetBits(avr.TCCR4A_COM4C1) - } - } - } - interrupt.Restore(mask) - case 5: - mask := interrupt.Disable() - switch channel { - case 0: // channel A, PL3 - if value == 0 { - avr.TCCR5A.ClearBits(avr.TCCR5A_COM5A1 | avr.TCCR5A_COM5A0) - } else { - value := uint16(value) - 1 // yes, this is safe (it relies on underflow) - avr.OCR5AH.Set(uint8(value >> 8)) - avr.OCR5AL.Set(uint8(value)) - if avr.PORTL.HasBits(1 << 3) { // is PL3 high? - // Yes, set the inverting bit. - avr.TCCR5A.SetBits(avr.TCCR5A_COM5A1 | avr.TCCR5A_COM5A0) - } else { - // No, output is non-inverting. - avr.TCCR5A.SetBits(avr.TCCR5A_COM5A1) - } - } - case 1: // channel B, PL4 - if value == 0 { - avr.TCCR5A.ClearBits(avr.TCCR5A_COM5B1 | avr.TCCR5A_COM5B0) - } else { - value := uint16(value) - 1 // yes, this is safe (it relies on underflow) - avr.OCR5BH.Set(uint8(value >> 8)) - avr.OCR5BL.Set(uint8(value)) - if avr.PORTL.HasBits(1 << 4) { // is PL4 high? - // Yes, set the inverting bit. - avr.TCCR5A.SetBits(avr.TCCR5A_COM5B1 | avr.TCCR5A_COM5B0) - } else { - // No, output is non-inverting. - avr.TCCR5A.SetBits(avr.TCCR5A_COM5B1) - } - } - case 2: // channel C, PL5 - if value == 0 { - avr.TCCR5A.ClearBits(avr.TCCR5A_COM5C1 | avr.TCCR5A_COM5C0) - } else { - value := uint16(value) - 1 // yes, this is safe (it relies on underflow) - avr.OCR5CH.Set(uint8(value >> 8)) - avr.OCR5CL.Set(uint8(value)) - if avr.PORTL.HasBits(1 << 5) { // is PL5 high? - // Yes, set the inverting bit. - avr.TCCR5A.SetBits(avr.TCCR5A_COM5C1 | avr.TCCR5A_COM5C0) - } else { - // No, output is non-inverting. - avr.TCCR5A.SetBits(avr.TCCR5A_COM5C1) - } - } - } - interrupt.Restore(mask) - } -} - -// SPI configuration -var SPI0 = &SPI{ - spcr: avr.SPCR, - spdr: avr.SPDR, - spsr: avr.SPSR, - sck: PB1, - sdo: PB2, - sdi: PB3, - cs: PB0} diff --git a/emb/machine/machine_atmega1284p.go b/emb/machine/machine_atmega1284p.go deleted file mode 100644 index db8fd65..0000000 --- a/emb/machine/machine_atmega1284p.go +++ /dev/null @@ -1,81 +0,0 @@ -//go:build avr && atmega1284p - -package machine - -import ( - "device/avr" - "runtime/volatile" -) - -const irq_USART0_RX = avr.IRQ_USART0_RX - -// Return the current CPU frequency in hertz. -func CPUFrequency() uint32 { - return 20000000 -} - -const ( - portA Pin = iota * 8 - portB - portC - portD -) - -const ( - PA0 = portA + 0 - PA1 = portA + 1 - PA2 = portA + 2 - PA3 = portA + 3 - PA4 = portA + 4 - PA5 = portA + 5 - PA6 = portA + 6 - PA7 = portA + 7 - PB0 = portB + 0 - PB1 = portB + 1 - PB2 = portB + 2 - PB3 = portB + 3 - PB4 = portB + 4 - PB5 = portB + 5 - PB6 = portB + 6 - PB7 = portB + 7 - PC0 = portC + 0 - PC1 = portC + 1 - PC2 = portC + 2 - PC3 = portC + 3 - PC4 = portC + 4 - PC5 = portC + 5 - PC6 = portC + 6 - PC7 = portC + 7 - PD0 = portD + 0 - PD1 = portD + 1 - PD2 = portD + 2 - PD3 = portD + 3 - PD4 = portD + 4 - PD5 = portD + 5 - PD6 = portD + 6 - PD7 = portD + 7 -) - -// getPortMask returns the PORTx register and mask for the pin. -func (p Pin) getPortMask() (*volatile.Register8, uint8) { - switch { - case p >= PA0 && p <= PA7: - return avr.PORTA, 1 << uint8(p-portA) - case p >= PB0 && p <= PB7: - return avr.PORTB, 1 << uint8(p-portB) - case p >= PC0 && p <= PC7: - return avr.PORTC, 1 << uint8(p-portC) - default: - return avr.PORTD, 1 << uint8(p-portD) - } -} - -// SPI configuration -var SPI0 = &SPI{ - spcr: avr.SPCR, - spsr: avr.SPSR, - spdr: avr.SPDR, - sck: PB7, - sdo: PB5, - sdi: PB6, - cs: PB4} diff --git a/emb/machine/machine_atmega2560.go b/emb/machine/machine_atmega2560.go deleted file mode 100644 index ede862a..0000000 --- a/emb/machine/machine_atmega2560.go +++ /dev/null @@ -1,141 +0,0 @@ -//go:build avr && atmega2560 - -package machine - -import ( - "device/avr" - "runtime/volatile" -) - -const irq_USART0_RX = avr.IRQ_USART0_RX -const irq_USART1_RX = avr.IRQ_USART1_RX -const irq_USART2_RX = avr.IRQ_USART2_RX -const irq_USART3_RX = avr.IRQ_USART3_RX - -const ( - portA Pin = iota * 8 - portB - portC - portD - portE - portF - portG - portH - portJ - portK - portL -) - -const ( - PA0 = portA + 0 - PA1 = portA + 1 - PA2 = portA + 2 - PA3 = portA + 3 - PA4 = portA + 4 - PA5 = portA + 5 - PA6 = portA + 6 - PA7 = portA + 7 - PB0 = portB + 0 - PB1 = portB + 1 - PB2 = portB + 2 - PB3 = portB + 3 - PB4 = portB + 4 - PB5 = portB + 5 - PB6 = portB + 6 - PB7 = portB + 7 - PC0 = portC + 0 - PC1 = portC + 1 - PC2 = portC + 2 - PC3 = portC + 3 - PC4 = portC + 4 - PC5 = portC + 5 - PC6 = portC + 6 - PC7 = portC + 7 - PD0 = portD + 0 - PD1 = portD + 1 - PD2 = portD + 2 - PD3 = portD + 3 - PD7 = portD + 7 - PE0 = portE + 0 - PE1 = portE + 1 - PE3 = portE + 3 - PE4 = portE + 4 - PE5 = portE + 5 - PE6 = portE + 6 - PF0 = portF + 0 - PF1 = portF + 1 - PF2 = portF + 2 - PF3 = portF + 3 - PF4 = portF + 4 - PF5 = portF + 5 - PF6 = portF + 6 - PF7 = portF + 7 - PG0 = portG + 0 - PG1 = portG + 1 - PG2 = portG + 2 - PG5 = portG + 5 - PH0 = portH + 0 - PH1 = portH + 1 - PH3 = portH + 3 - PH4 = portH + 4 - PH5 = portH + 5 - PH6 = portH + 6 - PJ0 = portJ + 0 - PJ1 = portJ + 1 - PK0 = portK + 0 - PK1 = portK + 1 - PK2 = portK + 2 - PK3 = portK + 3 - PK4 = portK + 4 - PK5 = portK + 5 - PK6 = portK + 6 - PK7 = portK + 7 - PL0 = portL + 0 - PL1 = portL + 1 - PL2 = portL + 2 - PL3 = portL + 3 - PL4 = portL + 4 - PL5 = portL + 5 - PL6 = portL + 6 - PL7 = portL + 7 -) - -// getPortMask returns the PORTx register and mask for the pin. -func (p Pin) getPortMask() (*volatile.Register8, uint8) { - switch { - case p >= PA0 && p <= PA7: - return avr.PORTA, 1 << uint8(p-portA) - case p >= PB0 && p <= PB7: - return avr.PORTB, 1 << uint8(p-portB) - case p >= PC0 && p <= PC7: - return avr.PORTC, 1 << uint8(p-portC) - case p >= PD0 && p <= PD7: - return avr.PORTD, 1 << uint8(p-portD) - case p >= PE0 && p <= PE6: - return avr.PORTE, 1 << uint8(p-portE) - case p >= PF0 && p <= PF7: - return avr.PORTF, 1 << uint8(p-portF) - case p >= PG0 && p <= PG5: - return avr.PORTG, 1 << uint8(p-portG) - case p >= PH0 && p <= PH6: - return avr.PORTH, 1 << uint8(p-portH) - case p >= PJ0 && p <= PJ1: - return avr.PORTJ, 1 << uint8(p-portJ) - case p >= PK0 && p <= PK7: - return avr.PORTK, 1 << uint8(p-portK) - case p >= PL0 && p <= PL7: - return avr.PORTL, 1 << uint8(p-portL) - default: - return avr.PORTA, 255 - } -} - -// SPI configuration -var SPI0 = &SPI{ - spcr: avr.SPCR, - spdr: avr.SPDR, - spsr: avr.SPSR, - sck: PB1, - sdo: PB2, - sdi: PB3, - cs: PB0} diff --git a/emb/machine/machine_atmega328.go b/emb/machine/machine_atmega328.go deleted file mode 100644 index c354ccb..0000000 --- a/emb/machine/machine_atmega328.go +++ /dev/null @@ -1,548 +0,0 @@ -//go:build avr && (atmega328p || atmega328pb) - -package machine - -import ( - "device/avr" - "runtime/interrupt" - "runtime/volatile" -) - -// PWM is one PWM peripheral, which consists of a counter and two output -// channels (that can be connected to two fixed pins). You can set the frequency -// using SetPeriod, but only for all the channels in this PWM peripheral at -// once. -type PWM struct { - num uint8 -} - -var ( - Timer0 = PWM{0} // 8 bit timer for PD5 and PD6 - Timer1 = PWM{1} // 16 bit timer for PB1 and PB2 - Timer2 = PWM{2} // 8 bit timer for PB3 and PD3 -) - -// Configure enables and configures this PWM. -// -// For the two 8 bit timers, there is only a limited number of periods -// available, namely the CPU frequency divided by 256 and again divided by 1, 8, -// 64, 256, or 1024. For a MCU running at 16MHz, this would be a period of 16µs, -// 128µs, 1024µs, 4096µs, or 16384µs. -func (pwm PWM) Configure(config PWMConfig) error { - switch pwm.num { - case 0, 2: // 8-bit timers (Timer/counter 0 and Timer/counter 2) - // Calculate the timer prescaler. - // While we could configure a flexible top, that would sacrifice one of - // the PWM output compare registers and thus a PWM channel. I've chosen - // to instead limit this timer to a fixed number of frequencies. - var prescaler uint8 - switch config.Period { - case 0, (uint64(1e9) * 256 * 1) / uint64(CPUFrequency()): - prescaler = 1 - case (uint64(1e9) * 256 * 8) / uint64(CPUFrequency()): - prescaler = 2 - case (uint64(1e9) * 256 * 64) / uint64(CPUFrequency()): - prescaler = 3 - case (uint64(1e9) * 256 * 256) / uint64(CPUFrequency()): - prescaler = 4 - case (uint64(1e9) * 256 * 1024) / uint64(CPUFrequency()): - prescaler = 5 - default: - return ErrPWMPeriodTooLong - } - - if pwm.num == 0 { - avr.TCCR0B.Set(prescaler) - // Set the PWM mode to fast PWM (mode = 3). - avr.TCCR0A.Set(avr.TCCR0A_WGM00 | avr.TCCR0A_WGM01) - // monotonic timer is using the same time as PWM:0 - // we must adjust internal settings of monotonic timer when PWM:0 settings changed - adjustMonotonicTimer() - } else { - avr.TCCR2B.Set(prescaler) - // Set the PWM mode to fast PWM (mode = 3). - avr.TCCR2A.Set(avr.TCCR2A_WGM20 | avr.TCCR2A_WGM21) - } - case 1: // Timer/counter 1 - // The top value is the number of PWM ticks a PWM period takes. It is - // initially picked assuming an unlimited counter top and no PWM - // prescaler. - var top uint64 - if config.Period == 0 { - // Use a top appropriate for LEDs. Picking a relatively low period - // here (0xff) for consistency with the other timers. - top = 0xff - } else { - // The formula below calculates the following formula, optimized: - // top = period * (CPUFrequency() / 1e9) - // By dividing the CPU frequency first (an operation that is easily - // optimized away) the period has less chance of overflowing. - top = config.Period * (uint64(CPUFrequency()) / 1000000) / 1000 - } - - avr.TCCR1A.Set(avr.TCCR1A_WGM11) - - // The ideal PWM period may be larger than would fit in the PWM counter, - // which is 16 bits (see maxTop). Therefore, try to make the PWM clock - // speed lower with a prescaler to make the top value fit the maximum - // top value. - const maxTop = 0x10000 - switch { - case top <= maxTop: - avr.TCCR1B.Set(3<<3 | 1) // no prescaling - case top/8 <= maxTop: - avr.TCCR1B.Set(3<<3 | 2) // divide by 8 - top /= 8 - case top/64 <= maxTop: - avr.TCCR1B.Set(3<<3 | 3) // divide by 64 - top /= 64 - case top/256 <= maxTop: - avr.TCCR1B.Set(3<<3 | 4) // divide by 256 - top /= 256 - case top/1024 <= maxTop: - avr.TCCR1B.Set(3<<3 | 5) // divide by 1024 - top /= 1024 - default: - return ErrPWMPeriodTooLong - } - - // A top of 0x10000 is at 100% duty cycle. Subtract one because the - // counter counts from 0, not 1 (avoiding an off-by-one). - top -= 1 - - avr.ICR1H.Set(uint8(top >> 8)) - avr.ICR1L.Set(uint8(top)) - } - return nil -} - -// SetPeriod updates the period of this PWM peripheral. -// To set a particular frequency, use the following formula: -// -// period = 1e9 / frequency -// -// If you use a period of 0, a period that works well for LEDs will be picked. -// -// SetPeriod will not change the prescaler, but also won't change the current -// value in any of the channels. This means that you may need to update the -// value for the particular channel. -// -// Note that you cannot pick any arbitrary period after the PWM peripheral has -// been configured. If you want to switch between frequencies, pick the lowest -// frequency (longest period) once when calling Configure and adjust the -// frequency here as needed. -func (pwm PWM) SetPeriod(period uint64) error { - if pwm.num != 1 { - return ErrPWMPeriodTooLong // TODO better error message - } - - // The top value is the number of PWM ticks a PWM period takes. It is - // initially picked assuming an unlimited counter top and no PWM - // prescaler. - var top uint64 - if period == 0 { - // Use a top appropriate for LEDs. Picking a relatively low period - // here (0xff) for consistency with the other timers. - top = 0xff - } else { - // The formula below calculates the following formula, optimized: - // top = period * (CPUFrequency() / 1e9) - // By dividing the CPU frequency first (an operation that is easily - // optimized away) the period has less chance of overflowing. - top = period * (uint64(CPUFrequency()) / 1000000) / 1000 - } - - prescaler := avr.TCCR1B.Get() & 0x7 - switch prescaler { - case 1: - top /= 1 - case 2: - top /= 8 - case 3: - top /= 64 - case 4: - top /= 256 - case 5: - top /= 1024 - } - - // A top of 0x10000 is at 100% duty cycle. Subtract one because the counter - // counts from 0, not 1 (avoiding an off-by-one). - top -= 1 - - if top > 0xffff { - return ErrPWMPeriodTooLong - } - - // Warning: this change is not atomic! - avr.ICR1H.Set(uint8(top >> 8)) - avr.ICR1L.Set(uint8(top)) - - // ... and because of that, set the counter back to zero to avoid most of - // the effects of this non-atomicity. - avr.TCNT1H.Set(0) - avr.TCNT1L.Set(0) - - return nil -} - -// Top returns the current counter top, for use in duty cycle calculation. It -// will only change with a call to Configure or SetPeriod, otherwise it is -// constant. -// -// The value returned here is hardware dependent. In general, it's best to treat -// it as an opaque value that can be divided by some number and passed to Set -// (see Set documentation for more information). -func (pwm PWM) Top() uint32 { - if pwm.num == 1 { - // Timer 1 has a configurable top value. - low := avr.ICR1L.Get() - high := avr.ICR1H.Get() - return uint32(high)<<8 | uint32(low) + 1 - } - // Other timers go from 0 to 0xff (0x100 or 256 in total). - return 256 -} - -// Counter returns the current counter value of the timer in this PWM -// peripheral. It may be useful for debugging. -func (pwm PWM) Counter() uint32 { - switch pwm.num { - case 0: - return uint32(avr.TCNT0.Get()) - case 1: - mask := interrupt.Disable() - low := avr.TCNT1L.Get() - high := avr.TCNT1H.Get() - interrupt.Restore(mask) - return uint32(high)<<8 | uint32(low) - case 2: - return uint32(avr.TCNT2.Get()) - } - // Unknown PWM. - return 0 -} - -// Period returns the used PWM period in nanoseconds. It might deviate slightly -// from the configured period due to rounding. -func (pwm PWM) Period() uint64 { - var prescaler uint8 - switch pwm.num { - case 0: - prescaler = avr.TCCR0B.Get() & 0x7 - case 1: - prescaler = avr.TCCR1B.Get() & 0x7 - case 2: - prescaler = avr.TCCR2B.Get() & 0x7 - } - top := uint64(pwm.Top()) - switch prescaler { - case 1: // prescaler 1 - return 1 * top * 1000 / uint64(CPUFrequency()/1e6) - case 2: // prescaler 8 - return 8 * top * 1000 / uint64(CPUFrequency()/1e6) - case 3: // prescaler 64 - return 64 * top * 1000 / uint64(CPUFrequency()/1e6) - case 4: // prescaler 256 - return 256 * top * 1000 / uint64(CPUFrequency()/1e6) - case 5: // prescaler 1024 - return 1024 * top * 1000 / uint64(CPUFrequency()/1e6) - default: // unknown clock source - return 0 - } -} - -// Channel returns a PWM channel for the given pin. -func (pwm PWM) Channel(pin Pin) (uint8, error) { - pin.Configure(PinConfig{Mode: PinOutput}) - pin.Low() - switch pwm.num { - case 0: - switch pin { - case PD6: // channel A - avr.TCCR0A.SetBits(avr.TCCR0A_COM0A1) - return 0, nil - case PD5: // channel B - avr.TCCR0A.SetBits(avr.TCCR0A_COM0B1) - return 1, nil - } - case 1: - switch pin { - case PB1: // channel A - avr.TCCR1A.SetBits(avr.TCCR1A_COM1A1) - return 0, nil - case PB2: // channel B - avr.TCCR1A.SetBits(avr.TCCR1A_COM1B1) - return 1, nil - } - case 2: - switch pin { - case PB3: // channel A - avr.TCCR2A.SetBits(avr.TCCR2A_COM2A1) - return 0, nil - case PD3: // channel B - avr.TCCR2A.SetBits(avr.TCCR2A_COM2B1) - return 1, nil - } - } - return 0, ErrInvalidOutputPin -} - -// SetInverting sets whether to invert the output of this channel. -// Without inverting, a 25% duty cycle would mean the output is high for 25% of -// the time and low for the rest. Inverting flips the output as if a NOT gate -// was placed at the output, meaning that the output would be 25% low and 75% -// high with a duty cycle of 25%. -// -// Note: the invert state may not be applied on the AVR until the next call to -// ch.Set(). -func (pwm PWM) SetInverting(channel uint8, inverting bool) { - switch pwm.num { - case 0: - switch channel { - case 0: // channel A - if inverting { - avr.PORTB.SetBits(1 << 6) // PB6 high - avr.TCCR0A.SetBits(avr.TCCR0A_COM0A0) - } else { - avr.PORTB.ClearBits(1 << 6) // PB6 low - avr.TCCR0A.ClearBits(avr.TCCR0A_COM0A0) - } - case 1: // channel B - if inverting { - avr.PORTB.SetBits(1 << 5) // PB5 high - avr.TCCR0A.SetBits(avr.TCCR0A_COM0B0) - } else { - avr.PORTB.ClearBits(1 << 5) // PB5 low - avr.TCCR0A.ClearBits(avr.TCCR0A_COM0B0) - } - } - case 1: - // Note: the COM1A0/COM1B0 bit is not set with the configuration below. - // It will be set the following call to Set(), however. - switch channel { - case 0: // channel A, PB1 - if inverting { - avr.PORTB.SetBits(1 << 1) // PB1 high - } else { - avr.PORTB.ClearBits(1 << 1) // PB1 low - } - case 1: // channel B, PB2 - if inverting { - avr.PORTB.SetBits(1 << 2) // PB2 high - } else { - avr.PORTB.ClearBits(1 << 2) // PB2 low - } - } - case 2: - switch channel { - case 0: // channel A - if inverting { - avr.PORTB.SetBits(1 << 3) // PB3 high - avr.TCCR2A.SetBits(avr.TCCR2A_COM2A0) - } else { - avr.PORTB.ClearBits(1 << 3) // PB3 low - avr.TCCR2A.ClearBits(avr.TCCR2A_COM2A0) - } - case 1: // channel B - if inverting { - avr.PORTD.SetBits(1 << 3) // PD3 high - avr.TCCR2A.SetBits(avr.TCCR2A_COM2B0) - } else { - avr.PORTD.ClearBits(1 << 3) // PD3 low - avr.TCCR2A.ClearBits(avr.TCCR2A_COM2B0) - } - } - } -} - -// Set updates the channel value. This is used to control the channel duty -// cycle, in other words the fraction of time the channel output is high (or low -// when inverted). For example, to set it to a 25% duty cycle, use: -// -// pwm.Set(channel, pwm.Top() / 4) -// -// pwm.Set(channel, 0) will set the output to low and pwm.Set(channel, -// pwm.Top()) will set the output to high, assuming the output isn't inverted. -func (pwm PWM) Set(channel uint8, value uint32) { - switch pwm.num { - case 0: - value := uint16(value) - switch channel { - case 0: // channel A - if value == 0 { - avr.TCCR0A.ClearBits(avr.TCCR0A_COM0A1) - } else { - avr.OCR0A.Set(uint8(value - 1)) - avr.TCCR0A.SetBits(avr.TCCR0A_COM0A1) - } - case 1: // channel B - if value == 0 { - avr.TCCR0A.ClearBits(avr.TCCR0A_COM0B1) - } else { - avr.OCR0B.Set(uint8(value) - 1) - avr.TCCR0A.SetBits(avr.TCCR0A_COM0B1) - } - } - // monotonic timer is using the same time as PWM:0 - // we must adjust internal settings of monotonic timer when PWM:0 settings changed - adjustMonotonicTimer() - case 1: - mask := interrupt.Disable() - switch channel { - case 0: // channel A, PB1 - if value == 0 { - avr.TCCR1A.ClearBits(avr.TCCR1A_COM1A1 | avr.TCCR1A_COM1A0) - } else { - value := uint16(value) - 1 // yes, this is safe (it relies on underflow) - avr.OCR1AH.Set(uint8(value >> 8)) - avr.OCR1AL.Set(uint8(value)) - if avr.PORTB.HasBits(1 << 1) { // is PB1 high? - // Yes, set the inverting bit. - avr.TCCR1A.SetBits(avr.TCCR1A_COM1A1 | avr.TCCR1A_COM1A0) - } else { - // No, output is non-inverting. - avr.TCCR1A.SetBits(avr.TCCR1A_COM1A1) - } - } - case 1: // channel B, PB2 - if value == 0 { - avr.TCCR1A.ClearBits(avr.TCCR1A_COM1B1 | avr.TCCR1A_COM1B0) - } else { - value := uint16(value) - 1 // yes, this is safe (it relies on underflow) - avr.OCR1BH.Set(uint8(value >> 8)) - avr.OCR1BL.Set(uint8(value)) - if avr.PORTB.HasBits(1 << 2) { // is PB2 high? - // Yes, set the inverting bit. - avr.TCCR1A.SetBits(avr.TCCR1A_COM1B1 | avr.TCCR1A_COM1B0) - } else { - // No, output is non-inverting. - avr.TCCR1A.SetBits(avr.TCCR1A_COM1B1) - } - } - } - interrupt.Restore(mask) - case 2: - value := uint16(value) - switch channel { - case 0: // channel A - if value == 0 { - avr.TCCR2A.ClearBits(avr.TCCR2A_COM2A1) - } else { - avr.OCR2A.Set(uint8(value - 1)) - avr.TCCR2A.SetBits(avr.TCCR2A_COM2A1) - } - case 1: // channel B - if value == 0 { - avr.TCCR2A.ClearBits(avr.TCCR2A_COM2B1) - } else { - avr.OCR2B.Set(uint8(value - 1)) - avr.TCCR2A.SetBits(avr.TCCR2A_COM2B1) - } - } - } -} - -// Pin Change Interrupts -type PinChange uint8 - -const ( - PinRising PinChange = 1 << iota - PinFalling - PinToggle = PinRising | PinFalling -) - -func (pin Pin) SetInterrupt(pinChange PinChange, callback func(Pin)) (err error) { - - switch { - case pin >= PB0 && pin <= PB7: - // PCMSK0 - PCINT0-7 - pinStates[0] = avr.PINB.Get() - pinIndex := pin - PB0 - if pinChange&PinRising > 0 { - pinCallbacks[0][pinIndex][0] = callback - } - if pinChange&PinFalling > 0 { - pinCallbacks[0][pinIndex][1] = callback - } - if callback != nil { - avr.PCMSK0.SetBits(1 << pinIndex) - } else { - avr.PCMSK0.ClearBits(1 << pinIndex) - } - avr.PCICR.SetBits(avr.PCICR_PCIE0) - interrupt.New(avr.IRQ_PCINT0, handlePCINT0Interrupts) - case pin >= PC0 && pin <= PC7: - // PCMSK1 - PCINT8-14 - pinStates[1] = avr.PINC.Get() - pinIndex := pin - PC0 - if pinChange&PinRising > 0 { - pinCallbacks[1][pinIndex][0] = callback - } - if pinChange&PinFalling > 0 { - pinCallbacks[1][pinIndex][1] = callback - } - if callback != nil { - avr.PCMSK1.SetBits(1 << pinIndex) - } else { - avr.PCMSK1.ClearBits(1 << pinIndex) - } - avr.PCICR.SetBits(avr.PCICR_PCIE1) - interrupt.New(avr.IRQ_PCINT1, handlePCINT1Interrupts) - case pin >= PD0 && pin <= PD7: - // PCMSK2 - PCINT16-23 - pinStates[2] = avr.PIND.Get() - pinIndex := pin - PD0 - if pinChange&PinRising > 0 { - pinCallbacks[2][pinIndex][0] = callback - } - if pinChange&PinFalling > 0 { - pinCallbacks[2][pinIndex][1] = callback - } - if callback != nil { - avr.PCMSK2.SetBits(1 << pinIndex) - } else { - avr.PCMSK2.ClearBits(1 << pinIndex) - } - avr.PCICR.SetBits(avr.PCICR_PCIE2) - interrupt.New(avr.IRQ_PCINT2, handlePCINT2Interrupts) - default: - return ErrInvalidInputPin - } - - return nil -} - -var pinCallbacks [3][8][2]func(Pin) -var pinStates [3]uint8 - -func handlePCINTInterrupts(intr uint8, port *volatile.Register8) { - current := port.Get() - change := pinStates[intr] ^ current - pinStates[intr] = current - for i := uint8(0); i < 8; i++ { - if (change>>i)&0x01 != 0x01 { - continue - } - pin := Pin(intr*8 + i) - value := pin.Get() - if value && pinCallbacks[intr][i][0] != nil { - pinCallbacks[intr][i][0](pin) - } - if !value && pinCallbacks[intr][i][1] != nil { - pinCallbacks[intr][i][1](pin) - } - } -} - -func handlePCINT0Interrupts(intr interrupt.Interrupt) { - handlePCINTInterrupts(0, avr.PINB) -} - -func handlePCINT1Interrupts(intr interrupt.Interrupt) { - handlePCINTInterrupts(1, avr.PINC) -} - -func handlePCINT2Interrupts(intr interrupt.Interrupt) { - handlePCINTInterrupts(2, avr.PIND) -} diff --git a/emb/machine/machine_atmega328p.go b/emb/machine/machine_atmega328p.go deleted file mode 100644 index 5bacfb8..0000000 --- a/emb/machine/machine_atmega328p.go +++ /dev/null @@ -1,60 +0,0 @@ -//go:build avr && atmega328p - -package machine - -import ( - "device/avr" - "runtime/volatile" -) - -const irq_USART0_RX = avr.IRQ_USART_RX - -// I2C0 is the only I2C interface on most AVRs. -var I2C0 = &I2C{ - srReg: avr.TWSR, - brReg: avr.TWBR, - crReg: avr.TWCR, - drReg: avr.TWDR, - srPS0: avr.TWSR_TWPS0, - srPS1: avr.TWSR_TWPS1, - crEN: avr.TWCR_TWEN, - crINT: avr.TWCR_TWINT, - crSTO: avr.TWCR_TWSTO, - crEA: avr.TWCR_TWEA, - crSTA: avr.TWCR_TWSTA, -} - -// SPI configuration -var SPI0 = &SPI{ - spcr: avr.SPCR, - spdr: avr.SPDR, - spsr: avr.SPSR, - - spcrR0: avr.SPCR_SPR0, - spcrR1: avr.SPCR_SPR1, - spcrCPHA: avr.SPCR_CPHA, - spcrCPOL: avr.SPCR_CPOL, - spcrDORD: avr.SPCR_DORD, - spcrSPE: avr.SPCR_SPE, - spcrMSTR: avr.SPCR_MSTR, - - spsrI2X: avr.SPSR_SPI2X, - spsrSPIF: avr.SPSR_SPIF, - - sck: PB5, - sdo: PB3, - sdi: PB4, - cs: PB2, -} - -// getPortMask returns the PORTx register and mask for the pin. -func (p Pin) getPortMask() (*volatile.Register8, uint8) { - switch { - case p >= PB0 && p <= PB7: // port B - return avr.PORTB, 1 << uint8(p-portB) - case p >= PC0 && p <= PC7: // port C - return avr.PORTC, 1 << uint8(p-portC) - default: // port D - return avr.PORTD, 1 << uint8(p-portD) - } -} diff --git a/emb/machine/machine_atmega328pb.go b/emb/machine/machine_atmega328pb.go deleted file mode 100644 index 935c581..0000000 --- a/emb/machine/machine_atmega328pb.go +++ /dev/null @@ -1,119 +0,0 @@ -//go:build avr && atmega328pb - -package machine - -import ( - "device/avr" - "runtime/interrupt" - "runtime/volatile" -) - -const irq_USART0_RX = avr.IRQ_USART0_RX -const irq_USART1_RX = avr.IRQ_USART1_RX - -var ( - UART1 = &_UART1 - _UART1 = UART{ - Buffer: NewRingBuffer(), - - dataReg: avr.UDR1, - baudRegH: avr.UBRR1H, - baudRegL: avr.UBRR1L, - statusRegA: avr.UCSR1A, - statusRegB: avr.UCSR1B, - statusRegC: avr.UCSR1C, - } -) - -func init() { - // Register the UART interrupt. - interrupt.New(irq_USART1_RX, _UART1.handleInterrupt) -} - -// I2C0 is the only I2C interface on most AVRs. -var I2C0 = &I2C{ - srReg: avr.TWSR0, - brReg: avr.TWBR0, - crReg: avr.TWCR0, - drReg: avr.TWDR0, - srPS0: avr.TWSR0_TWPS0, - srPS1: avr.TWSR0_TWPS1, - crEN: avr.TWCR0_TWEN, - crINT: avr.TWCR0_TWINT, - crSTO: avr.TWCR0_TWSTO, - crEA: avr.TWCR0_TWEA, - crSTA: avr.TWCR0_TWSTA, -} - -var I2C1 = &I2C{ - srReg: avr.TWSR1, - brReg: avr.TWBR1, - crReg: avr.TWCR1, - drReg: avr.TWDR1, - srPS0: avr.TWSR1_TWPS10, - srPS1: avr.TWSR1_TWPS11, - crEN: avr.TWCR1_TWEN1, - crINT: avr.TWCR1_TWINT1, - crSTO: avr.TWCR1_TWSTO1, - crEA: avr.TWCR1_TWEA1, - crSTA: avr.TWCR1_TWSTA1, -} - -// SPI configuration -var SPI0 = &SPI{ - spcr: avr.SPCR0, - spdr: avr.SPDR0, - spsr: avr.SPSR0, - - spcrR0: avr.SPCR0_SPR0, - spcrR1: avr.SPCR0_SPR1, - spcrCPHA: avr.SPCR0_CPHA, - spcrCPOL: avr.SPCR0_CPOL, - spcrDORD: avr.SPCR0_DORD, - spcrSPE: avr.SPCR0_SPE, - spcrMSTR: avr.SPCR0_MSTR, - - spsrI2X: avr.SPSR0_SPI2X, - spsrSPIF: avr.SPSR0_SPIF, - - sck: PB5, - sdo: PB3, - sdi: PB4, - cs: PB2, -} - -var SPI1 = &SPI{ - spcr: avr.SPCR1, - spdr: avr.SPDR1, - spsr: avr.SPSR1, - - spcrR0: avr.SPCR1_SPR10, - spcrR1: avr.SPCR1_SPR11, - spcrCPHA: avr.SPCR1_CPHA1, - spcrCPOL: avr.SPCR1_CPOL1, - spcrDORD: avr.SPCR1_DORD1, - spcrSPE: avr.SPCR1_SPE1, - spcrMSTR: avr.SPCR1_MSTR1, - - spsrI2X: avr.SPSR1_SPI2X1, - spsrSPIF: avr.SPSR1_SPIF1, - - sck: PC1, - sdo: PE3, - sdi: PC0, - cs: PE2, -} - -// getPortMask returns the PORTx register and mask for the pin. -func (p Pin) getPortMask() (*volatile.Register8, uint8) { - switch { - case p >= PB0 && p <= PB7: // port B - return avr.PORTB, 1 << uint8(p-portB) - case p >= PC0 && p <= PC7: // port C - return avr.PORTC, 1 << uint8(p-portC) - case p >= PD0 && p <= PD7: // port D - return avr.PORTD, 1 << uint8(p-portD) - default: // port E - return avr.PORTE, 1 << uint8(p-portE) - } -} diff --git a/emb/machine/machine_atmega32u4.go b/emb/machine/machine_atmega32u4.go deleted file mode 100644 index 8b3faab..0000000 --- a/emb/machine/machine_atmega32u4.go +++ /dev/null @@ -1,76 +0,0 @@ -//go:build avr && atmega32u4 - -package machine - -import ( - "device/avr" - "runtime/volatile" -) - -const ( - // Note: start at port B because there is no port A. - portB Pin = iota * 8 - portC - portD - portE - portF -) - -const ( - PB0 = portB + 0 - PB1 = portB + 1 // peripherals: Timer1 channel A - PB2 = portB + 2 // peripherals: Timer1 channel B - PB3 = portB + 3 // peripherals: Timer2 channel A - PB4 = portB + 4 - PB5 = portB + 5 - PB6 = portB + 6 - PB7 = portB + 7 - PC0 = portC + 0 - PC1 = portC + 1 - PC2 = portC + 2 - PC3 = portC + 3 - PC4 = portC + 4 - PC5 = portC + 5 - PC6 = portC + 6 - PC7 = portC + 7 - PD0 = portD + 0 - PD1 = portD + 1 - PD2 = portD + 2 - PD3 = portD + 3 - PD4 = portD + 4 - PD5 = portD + 5 - PD6 = portD + 6 - PD7 = portD + 7 - PE0 = portE + 0 - PE1 = portE + 1 - PE2 = portE + 2 - PE3 = portE + 3 - PE4 = portE + 4 - PE5 = portE + 5 - PE6 = portE + 6 - PE7 = portE + 7 - PF0 = portF + 0 - PF1 = portF + 1 - PF2 = portF + 2 - PF3 = portF + 3 - PF4 = portF + 4 - PF5 = portF + 5 - PF6 = portF + 6 - PF7 = portF + 7 -) - -// getPortMask returns the PORTx register and mask for the pin. -func (p Pin) getPortMask() (*volatile.Register8, uint8) { - switch { - case p >= PB0 && p <= PB7: // port B - return avr.PORTB, 1 << uint8(p-portB) - case p >= PC0 && p <= PC7: // port C - return avr.PORTC, 1 << uint8(p-portC) - case p >= PD0 && p <= PD7: // port D - return avr.PORTD, 1 << uint8(p-portD) - case p >= PE0 && p <= PE7: // port E - return avr.PORTE, 1 << uint8(p-portE) - default: // port F - return avr.PORTF, 1 << uint8(p-portF) - } -} diff --git a/emb/machine/machine_atsam.go b/emb/machine/machine_atsam.go deleted file mode 100644 index ad2f073..0000000 --- a/emb/machine/machine_atsam.go +++ /dev/null @@ -1,31 +0,0 @@ -//go:build sam - -package machine - -import ( - "runtime/volatile" - "unsafe" -) - -var deviceID [16]byte - -// DeviceID returns an identifier that is unique within -// a particular chipset. -// -// The identity is one burnt into the MCU itself, or the -// flash chip at time of manufacture. -// -// It's possible that two different vendors may allocate -// the same DeviceID, so callers should take this into -// account if needing to generate a globally unique id. -// -// The length of the hardware ID is vendor-specific, but -// 8 bytes (64 bits) and 16 bytes (128 bits) are common. -func DeviceID() []byte { - for i := 0; i < len(deviceID); i++ { - word := (*volatile.Register32)(unsafe.Pointer(deviceIDAddr[i/4])).Get() - deviceID[i] = byte(word >> ((i % 4) * 8)) - } - - return deviceID[:] -} diff --git a/emb/machine/machine_atsamd21.go b/emb/machine/machine_atsamd21.go deleted file mode 100644 index b46dcef..0000000 --- a/emb/machine/machine_atsamd21.go +++ /dev/null @@ -1,2090 +0,0 @@ -//go:build sam && atsamd21 - -// Peripheral abstraction layer for the atsamd21. -// -// Datasheet: -// http://ww1.microchip.com/downloads/en/DeviceDoc/SAMD21-Family-DataSheet-DS40001882D.pdf -package machine - -import ( - "device/arm" - "device/sam" - "errors" - "internal/binary" - "runtime/interrupt" - "unsafe" -) - -const deviceName = sam.Device - -// DS40001882F, Section 10.3.3: Serial Number -var deviceIDAddr = []uintptr{0x0080A00C, 0x0080A040, 0x0080A044, 0x0080A048} - -const ( - PinAnalog PinMode = 1 - PinSERCOM PinMode = 2 - PinSERCOMAlt PinMode = 3 - PinTimer PinMode = 4 - PinTimerAlt PinMode = 5 - PinCom PinMode = 6 - //PinAC_CLK PinMode = 7 - PinDigital PinMode = 8 - PinInput PinMode = 9 - PinInputPullup PinMode = 10 - PinOutput PinMode = 11 - PinTCC PinMode = PinTimer - PinTCCAlt PinMode = PinTimerAlt - PinInputPulldown PinMode = 12 -) - -type PinChange uint8 - -// Pin change interrupt constants for SetInterrupt. -const ( - PinRising PinChange = sam.EIC_CONFIG_SENSE0_RISE - PinFalling PinChange = sam.EIC_CONFIG_SENSE0_FALL - PinToggle PinChange = sam.EIC_CONFIG_SENSE0_BOTH -) - -// Callbacks to be called for pins configured with SetInterrupt. Unfortunately, -// we also need to keep track of which interrupt channel is used by which pin, -// as the only alternative would be iterating through all pins. -// -// We're using the magic constant 16 here because the SAM D21 has 16 interrupt -// channels configurable for pins. -var ( - interruptPins [16]Pin // warning: the value is invalid when pinCallbacks[i] is not set! - pinCallbacks [16]func(Pin) -) - -const ( - pinPadMapSERCOM0Pad0 byte = (0x10 << 1) | 0x00 - pinPadMapSERCOM1Pad0 byte = (0x20 << 1) | 0x00 - pinPadMapSERCOM2Pad0 byte = (0x30 << 1) | 0x00 - pinPadMapSERCOM3Pad0 byte = (0x40 << 1) | 0x00 - pinPadMapSERCOM4Pad0 byte = (0x50 << 1) | 0x00 - pinPadMapSERCOM5Pad0 byte = (0x60 << 1) | 0x00 - pinPadMapSERCOM0Pad2 byte = (0x10 << 1) | 0x10 - pinPadMapSERCOM1Pad2 byte = (0x20 << 1) | 0x10 - pinPadMapSERCOM2Pad2 byte = (0x30 << 1) | 0x10 - pinPadMapSERCOM3Pad2 byte = (0x40 << 1) | 0x10 - pinPadMapSERCOM4Pad2 byte = (0x50 << 1) | 0x10 - pinPadMapSERCOM5Pad2 byte = (0x60 << 1) | 0x10 - - pinPadMapSERCOM0AltPad0 byte = (0x01 << 1) | 0x00 - pinPadMapSERCOM1AltPad0 byte = (0x02 << 1) | 0x00 - pinPadMapSERCOM2AltPad0 byte = (0x03 << 1) | 0x00 - pinPadMapSERCOM3AltPad0 byte = (0x04 << 1) | 0x00 - pinPadMapSERCOM4AltPad0 byte = (0x05 << 1) | 0x00 - pinPadMapSERCOM5AltPad0 byte = (0x06 << 1) | 0x00 - pinPadMapSERCOM0AltPad2 byte = (0x01 << 1) | 0x01 - pinPadMapSERCOM1AltPad2 byte = (0x02 << 1) | 0x01 - pinPadMapSERCOM2AltPad2 byte = (0x03 << 1) | 0x01 - pinPadMapSERCOM3AltPad2 byte = (0x04 << 1) | 0x01 - pinPadMapSERCOM4AltPad2 byte = (0x05 << 1) | 0x01 - pinPadMapSERCOM5AltPad2 byte = (0x06 << 1) | 0x01 -) - -// pinPadMapping lists which pins have which SERCOMs attached to them. -// The encoding is rather dense, with each byte encoding two pins and both -// SERCOM and SERCOM-ALT. -// -// Observations: -// - There are six SERCOMs. Those SERCOM numbers can be encoded in 3 bits. -// - Even pad numbers are always on even pins, and odd pad numbers are always on -// odd pins. -// - Pin pads come in pairs. If PA00 has pad 0, then PA01 has pad 1. -// -// With this information, we can encode SERCOM pin/pad numbers much more -// efficiently. First of all, due to pads coming in pairs, we can ignore half -// the pins: the information for an odd pin can be calculated easily from the -// preceding even pin. And second, if odd pads are always on odd pins and even -// pads on even pins, we can drop a single bit from the pad number. -// -// Each byte below is split in two nibbles. The 4 high bits are for SERCOM and -// the 4 low bits are for SERCOM-ALT. Of each nibble, the 3 high bits encode the -// SERCOM + 1 while the low bit encodes whether this is PAD0 or PAD2 (0 means -// PAD0, 1 means PAD2). It encodes SERCOM + 1 instead of just the SERCOM number, -// to make it easy to check whether a nibble is set at all. -var pinPadMapping = [32]byte{ - // page 21 - PA00 / 2: 0 | pinPadMapSERCOM1AltPad0, - PB08 / 2: 0 | pinPadMapSERCOM4AltPad0, - PA04 / 2: 0 | pinPadMapSERCOM0AltPad0, - PA06 / 2: 0 | pinPadMapSERCOM0AltPad2, - PA08 / 2: pinPadMapSERCOM0Pad0 | pinPadMapSERCOM2AltPad0, - PA10 / 2: pinPadMapSERCOM0Pad2 | pinPadMapSERCOM2AltPad2, - - // page 22 - PB10 / 2: 0 | pinPadMapSERCOM4AltPad2, - PB12 / 2: pinPadMapSERCOM4Pad0 | 0, - PB14 / 2: pinPadMapSERCOM4Pad2 | 0, - PA12 / 2: pinPadMapSERCOM2Pad0 | pinPadMapSERCOM4AltPad0, - PA14 / 2: pinPadMapSERCOM2Pad2 | pinPadMapSERCOM4AltPad2, - PA16 / 2: pinPadMapSERCOM1Pad0 | pinPadMapSERCOM3AltPad0, - PA18 / 2: pinPadMapSERCOM1Pad2 | pinPadMapSERCOM3AltPad2, - PB16 / 2: pinPadMapSERCOM5Pad0 | 0, - PA20 / 2: pinPadMapSERCOM5Pad2 | pinPadMapSERCOM3AltPad2, - PA22 / 2: pinPadMapSERCOM3Pad0 | pinPadMapSERCOM5AltPad0, - PA24 / 2: pinPadMapSERCOM3Pad2 | pinPadMapSERCOM5AltPad2, - - // page 23 - PB22 / 2: 0 | pinPadMapSERCOM5AltPad2, - PA30 / 2: 0 | pinPadMapSERCOM1AltPad2, - PB30 / 2: 0 | pinPadMapSERCOM5AltPad0, - PB00 / 2: 0 | pinPadMapSERCOM5AltPad2, - PB02 / 2: 0 | pinPadMapSERCOM5AltPad0, -} - -// findPinPadMapping looks up the pad number and the pinmode for a given pin, -// given a SERCOM number. The result can either be SERCOM, SERCOM-ALT, or "not -// found" (indicated by returning ok=false). The pad number is returned to -// calculate the DOPO/DIPO bitfields of the various serial peripherals. -func findPinPadMapping(sercom uint8, pin Pin) (pinMode PinMode, pad uint32, ok bool) { - if int(pin)/2 >= len(pinPadMapping) { - // This is probably NoPin, for which no mapping is available. - return - } - - nibbles := pinPadMapping[pin/2] - upper := nibbles >> 4 - lower := nibbles & 0xf - - if upper != 0 { - // SERCOM - if (upper>>1)-1 == sercom { - pinMode = PinSERCOM - pad |= uint32((upper & 1) << 1) - ok = true - } - } - if lower != 0 { - // SERCOM-ALT - if (lower>>1)-1 == sercom { - pinMode = PinSERCOMAlt - pad |= uint32((lower & 1) << 1) - ok = true - } - } - - if ok { - // The lower bit of the pad is the same as the lower bit of the pin number. - pad |= uint32(pin & 1) - } - return -} - -// SetInterrupt sets an interrupt to be executed when a particular pin changes -// state. The pin should already be configured as an input, including a pull up -// or down if no external pull is provided. -// -// This call will replace a previously set callback on this pin. You can pass a -// nil func to unset the pin change interrupt. If you do so, the change -// parameter is ignored and can be set to any value (such as 0). -func (p Pin) SetInterrupt(change PinChange, callback func(Pin)) error { - // Most pins follow a common pattern where the EXTINT value is the pin - // number modulo 16. However, there are a few exceptions, as you can see - // below. - extint := uint8(0) - switch p { - case PA08: - // Connected to NMI. This is not currently supported. - return ErrInvalidInputPin - case PA24: - extint = 12 - case PA25: - extint = 13 - case PA27: - extint = 15 - case PA28: - extint = 8 - case PA30: - extint = 10 - case PA31: - extint = 11 - default: - // All other pins follow a normal pattern. - extint = uint8(p) % 16 - } - - if callback == nil { - // Disable this pin interrupt (if it was enabled). - sam.EIC.INTENCLR.Set(1 << extint) - if pinCallbacks[extint] != nil { - pinCallbacks[extint] = nil - } - return nil - } - - if pinCallbacks[extint] != nil { - // The pin was already configured. - // To properly re-configure a pin, unset it first and set a new - // configuration. - return ErrNoPinChangeChannel - } - pinCallbacks[extint] = callback - interruptPins[extint] = p - - if sam.EIC.CTRL.Get() == 0 { - // EIC peripheral has not yet been initialized. Initialize it now. - - // The EIC needs two clocks: CLK_EIC_APB and GCLK_EIC. CLK_EIC_APB is - // enabled by default, so doesn't have to be re-enabled. The other is - // required for detecting edges and must be enabled manually. - sam.GCLK.CLKCTRL.Set(sam.GCLK_CLKCTRL_ID_EIC<= 8 { - addr = &sam.EIC.CONFIG1 - } - pos := (extint % 8) * 4 // bit position in register - addr.ReplaceBits(uint32(change), 0xf, pos) - - // Enable external interrupt for this pin. - sam.EIC.INTENSET.Set(1 << extint) - - // Set the PMUXEN flag, while keeping the INEN and PULLEN flags (if they - // were set before). This avoids clearing the pin pull mode while - // configuring the pin interrupt. - p.setPinCfg(sam.PORT_PINCFG0_PMUXEN | (p.getPinCfg() & (sam.PORT_PINCFG0_INEN | sam.PORT_PINCFG0_PULLEN))) - if p&1 > 0 { - // odd pin, so save the even pins - val := p.getPMux() & sam.PORT_PMUX0_PMUXE_Msk - p.setPMux(val | (sam.PORT_PMUX0_PMUXO_A << sam.PORT_PMUX0_PMUXO_Pos)) - } else { - // even pin, so save the odd pins - val := p.getPMux() & sam.PORT_PMUX0_PMUXO_Msk - p.setPMux(val | (sam.PORT_PMUX0_PMUXE_A << sam.PORT_PMUX0_PMUXE_Pos)) - } - - interrupt.New(sam.IRQ_EIC, func(interrupt.Interrupt) { - flags := sam.EIC.INTFLAG.Get() - sam.EIC.INTFLAG.Set(flags) // clear interrupt - for i := uint(0); i < 16; i++ { // there are 16 channels - if flags&(1<>3) & uint16(0x7) - - // ADC Linearity bits 4:0 - linearity0Fuse := *(*uint32)(unsafe.Pointer(uintptr(0x00806020))) - linearity := uint16(linearity0Fuse>>27) & uint16(0x1f) - - // ADC Linearity bits 7:5 - linearity1Fuse := *(*uint32)(unsafe.Pointer(uintptr(0x00806020) + 4)) - linearity |= uint16(linearity1Fuse) & uint16(0x7) << 5 - - // set calibration - sam.ADC.CALIB.Set((bias << 8) | linearity) -} - -// Configure configures a ADC pin to be able to be used to read data. -func (a ADC) Configure(config ADCConfig) { - - // Wait for synchronization - waitADCSync() - - var resolution uint32 - switch config.Resolution { - case 8: - resolution = sam.ADC_CTRLB_RESSEL_8BIT - case 10: - resolution = sam.ADC_CTRLB_RESSEL_10BIT - case 12: - resolution = sam.ADC_CTRLB_RESSEL_12BIT - case 16: - resolution = sam.ADC_CTRLB_RESSEL_16BIT - default: - resolution = sam.ADC_CTRLB_RESSEL_12BIT - } - // Divide Clock by 32 with 12 bits resolution as default - sam.ADC.CTRLB.Set((sam.ADC_CTRLB_PRESCALER_DIV32 << sam.ADC_CTRLB_PRESCALER_Pos) | - uint16(resolution<> sam.ADC_CTRLB_RESSEL_Pos { - case sam.ADC_CTRLB_RESSEL_8BIT: - val = val << 8 - case sam.ADC_CTRLB_RESSEL_10BIT: - val = val << 6 - case sam.ADC_CTRLB_RESSEL_16BIT: - val = val << 4 - case sam.ADC_CTRLB_RESSEL_12BIT: - val = val << 4 - } - return val -} - -func (a ADC) getADCChannel() uint8 { - switch a.Pin { - case PA02: - return 0 - case PA03: - return 1 - case PB04: - return 12 - case PB05: - return 13 - case PB06: - return 14 - case PB07: - return 15 - case PB08: - return 2 - case PB09: - return 3 - case PA04: - return 4 - case PA05: - return 5 - case PA06: - return 6 - case PA07: - return 7 - case PA08: - return 16 - case PA09: - return 17 - case PA10: - return 18 - case PA11: - return 19 - case PB00: - return 8 - case PB01: - return 9 - case PB02: - return 10 - case PB03: - return 11 - default: - return 0 - } -} - -func waitADCSync() { - for sam.ADC.STATUS.HasBits(sam.ADC_STATUS_SYNCBUSY) { - } -} - -// UART on the SAMD21. -type UART struct { - Buffer *RingBuffer - Bus *sam.SERCOM_USART_Type - SERCOM uint8 - Interrupt interrupt.Interrupt -} - -const ( - sampleRate16X = 16 - lsbFirst = 1 -) - -// Configure the UART. -func (uart *UART) Configure(config UARTConfig) error { - // Default baud rate to 115200. - if config.BaudRate == 0 { - config.BaudRate = 115200 - } - - // Use default pins if pins are not set. - if config.TX == 0 && config.RX == 0 { - // use default pins - config.TX = UART_TX_PIN - config.RX = UART_RX_PIN - } - - // Determine transmit pinout. - txPinMode, txPad, ok := findPinPadMapping(uart.SERCOM, config.TX) - if !ok { - return ErrInvalidOutputPin - } - var txPadOut uint32 - // See table 25-9 of the datasheet (page 459) for how pads are mapped to - // pinout values. - switch txPad { - case 0: - txPadOut = 0 - case 2: - txPadOut = 1 - default: - // this should be a flow control (RTS/CTS) pin - return ErrInvalidOutputPin - } - - // Determine receive pinout. - rxPinMode, rxPad, ok := findPinPadMapping(uart.SERCOM, config.RX) - if !ok { - return ErrInvalidInputPin - } - // As you can see in table 25-8 on page 459 of the datasheet, input pins - // are mapped directly. - rxPadOut := rxPad - - // configure pins - config.TX.Configure(PinConfig{Mode: txPinMode}) - config.RX.Configure(PinConfig{Mode: rxPinMode}) - - // configure RTS/CTS pins if provided - if config.RTS != 0 && config.CTS != 0 { - rtsPinMode, _, ok := findPinPadMapping(uart.SERCOM, config.RTS) - if !ok { - return ErrInvalidOutputPin - } - - ctsPinMode, _, ok := findPinPadMapping(uart.SERCOM, config.CTS) - if !ok { - return ErrInvalidInputPin - } - - // See table 25-9 of the datasheet (page 459) for how pads are mapped to - // pinout values. - if txPadOut == 1 { - return ErrInvalidOutputPin - } - txPadOut = 2 - - config.RTS.Configure(PinConfig{Mode: rtsPinMode}) - config.CTS.Configure(PinConfig{Mode: ctsPinMode}) - } - - // reset SERCOM0 - uart.Bus.CTRLA.SetBits(sam.SERCOM_USART_CTRLA_SWRST) - for uart.Bus.CTRLA.HasBits(sam.SERCOM_USART_CTRLA_SWRST) || - uart.Bus.SYNCBUSY.HasBits(sam.SERCOM_USART_SYNCBUSY_SWRST) { - } - - // set UART mode/sample rate - // SERCOM_USART_CTRLA_MODE(mode) | - // SERCOM_USART_CTRLA_SAMPR(sampleRate); - uart.Bus.CTRLA.Set((sam.SERCOM_USART_CTRLA_MODE_USART_INT_CLK << sam.SERCOM_USART_CTRLA_MODE_Pos) | - (1 << sam.SERCOM_USART_CTRLA_SAMPR_Pos)) // sample rate of 16x - - // Set baud rate - uart.SetBaudRate(config.BaudRate) - - // setup UART frame - // SERCOM_USART_CTRLA_FORM( (parityMode == SERCOM_NO_PARITY ? 0 : 1) ) | - // dataOrder << SERCOM_USART_CTRLA_DORD_Pos; - uart.Bus.CTRLA.SetBits((0 << sam.SERCOM_USART_CTRLA_FORM_Pos) | // no parity - (lsbFirst << sam.SERCOM_USART_CTRLA_DORD_Pos)) // data order - - // set UART stop bits/parity - // SERCOM_USART_CTRLB_CHSIZE(charSize) | - // nbStopBits << SERCOM_USART_CTRLB_SBMODE_Pos | - // (parityMode == SERCOM_NO_PARITY ? 0 : parityMode) << SERCOM_USART_CTRLB_PMODE_Pos; //If no parity use default value - uart.Bus.CTRLB.SetBits((0 << sam.SERCOM_USART_CTRLB_CHSIZE_Pos) | // 8 bits is 0 - (0 << sam.SERCOM_USART_CTRLB_SBMODE_Pos) | // 1 stop bit is zero - (0 << sam.SERCOM_USART_CTRLB_PMODE_Pos)) // no parity - - // set UART pads. This is not same as pins... - // SERCOM_USART_CTRLA_TXPO(txPad) | - // SERCOM_USART_CTRLA_RXPO(rxPad); - uart.Bus.CTRLA.SetBits((txPadOut << sam.SERCOM_USART_CTRLA_TXPO_Pos) | - (rxPadOut << sam.SERCOM_USART_CTRLA_RXPO_Pos)) - - // Enable Transceiver and Receiver - //sercom->USART.CTRLB.reg |= SERCOM_USART_CTRLB_TXEN | SERCOM_USART_CTRLB_RXEN ; - uart.Bus.CTRLB.SetBits(sam.SERCOM_USART_CTRLB_TXEN | sam.SERCOM_USART_CTRLB_RXEN) - - // Enable USART1 port. - // sercom->USART.CTRLA.bit.ENABLE = 0x1u; - uart.Bus.CTRLA.SetBits(sam.SERCOM_USART_CTRLA_ENABLE) - for uart.Bus.SYNCBUSY.HasBits(sam.SERCOM_USART_SYNCBUSY_ENABLE) { - } - - // setup interrupt on receive - uart.Bus.INTENSET.Set(sam.SERCOM_USART_INTENSET_RXC) - - // Enable RX IRQ. - uart.Interrupt.Enable() - - return nil -} - -// SetBaudRate sets the communication speed for the UART. -func (uart *UART) SetBaudRate(br uint32) { - // Asynchronous fractional mode (Table 24-2 in datasheet) - // BAUD = fref / (sampleRateValue * fbaud) - // (multiply by 8, to calculate fractional piece) - // uint32_t baudTimes8 = (SystemCoreClock * 8) / (16 * baudrate); - baud := (CPUFrequency() * 8) / (sampleRate16X * br) - - // sercom->USART.BAUD.FRAC.FP = (baudTimes8 % 8); - // sercom->USART.BAUD.FRAC.BAUD = (baudTimes8 / 8); - uart.Bus.BAUD.Set(uint16(((baud % 8) << sam.SERCOM_USART_BAUD_FRAC_MODE_FP_Pos) | - ((baud / 8) << sam.SERCOM_USART_BAUD_FRAC_MODE_BAUD_Pos))) -} - -// WriteByte writes a byte of data to the UART. -func (uart *UART) writeByte(c byte) error { - // wait until ready to receive - for !uart.Bus.INTFLAG.HasBits(sam.SERCOM_USART_INTFLAG_DRE) { - } - uart.Bus.DATA.Set(uint16(c)) - return nil -} - -func (uart *UART) flush() {} - -// handleInterrupt should be called from the appropriate interrupt handler for -// this UART instance. -func (uart *UART) handleInterrupt(interrupt.Interrupt) { - // should reset IRQ - uart.Receive(byte((uart.Bus.DATA.Get() & 0xFF))) - uart.Bus.INTFLAG.SetBits(sam.SERCOM_USART_INTFLAG_RXC) -} - -// I2C on the SAMD21. -type I2C struct { - Bus *sam.SERCOM_I2CM_Type - SERCOM uint8 -} - -// I2CConfig is used to store config info for I2C. -type I2CConfig struct { - Frequency uint32 - SCL Pin - SDA Pin -} - -const ( - // Default rise time in nanoseconds, based on 4.7K ohm pull up resistors - riseTimeNanoseconds = 125 - - // wire bus states - wireUnknownState = 0 - wireIdleState = 1 - wireOwnerState = 2 - wireBusyState = 3 - - // wire commands - wireCmdNoAction = 0 - wireCmdRepeatStart = 1 - wireCmdRead = 2 - wireCmdStop = 3 -) - -const i2cTimeout = 1000 - -// 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 - } - if config.SDA == 0 && config.SCL == 0 { - config.SDA = SDA_PIN - config.SCL = SCL_PIN - } - - sclPinMode, sclPad, ok := findPinPadMapping(i2c.SERCOM, config.SCL) - if !ok || sclPad != 1 { - // SCL must be on pad 1, according to section 27.5 of the datasheet. - // Note: this is not an exhaustive test for I2C support on the pin: not - // all pins support I2C. - return ErrInvalidClockPin - } - sdaPinMode, sdaPad, ok := findPinPadMapping(i2c.SERCOM, config.SDA) - if !ok || sdaPad != 0 { - // SDA must be on pad 0, according to section 27.5 of the datasheet. - // Note: this is not an exhaustive test for I2C support on the pin: not - // all pins support I2C. - return ErrInvalidDataPin - } - - // reset SERCOM - i2c.Bus.CTRLA.SetBits(sam.SERCOM_I2CM_CTRLA_SWRST) - for i2c.Bus.CTRLA.HasBits(sam.SERCOM_I2CM_CTRLA_SWRST) || - i2c.Bus.SYNCBUSY.HasBits(sam.SERCOM_I2CM_SYNCBUSY_SWRST) { - } - - // Set i2c controller mode - //SERCOM_I2CM_CTRLA_MODE( I2C_MASTER_OPERATION ) - i2c.Bus.CTRLA.Set(sam.SERCOM_I2CM_CTRLA_MODE_I2C_MASTER << sam.SERCOM_I2CM_CTRLA_MODE_Pos) // | - - i2c.SetBaudRate(config.Frequency) - - // Enable I2CM port. - // sercom->USART.CTRLA.bit.ENABLE = 0x1u; - i2c.Bus.CTRLA.SetBits(sam.SERCOM_I2CM_CTRLA_ENABLE) - for i2c.Bus.SYNCBUSY.HasBits(sam.SERCOM_I2CM_SYNCBUSY_ENABLE) { - } - - // set bus idle mode - i2c.Bus.STATUS.SetBits(wireIdleState << sam.SERCOM_I2CM_STATUS_BUSSTATE_Pos) - for i2c.Bus.SYNCBUSY.HasBits(sam.SERCOM_I2CM_SYNCBUSY_SYSOP) { - } - - // enable pins - config.SDA.Configure(PinConfig{Mode: sdaPinMode}) - config.SCL.Configure(PinConfig{Mode: sclPinMode}) - - return nil -} - -// SetBaudRate sets the communication speed for I2C. -func (i2c *I2C) SetBaudRate(br uint32) error { - // Synchronous arithmetic baudrate, via Arduino SAMD implementation: - // SystemCoreClock / ( 2 * baudrate) - 5 - (((SystemCoreClock / 1000000) * WIRE_RISE_TIME_NANOSECONDS) / (2 * 1000)); - baud := CPUFrequency()/(2*br) - 5 - (((CPUFrequency() / 1000000) * riseTimeNanoseconds) / (2 * 1000)) - i2c.Bus.BAUD.Set(baud) - 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 { - var err error - if len(w) != 0 { - // send start/address for write - i2c.sendAddress(addr, true) - - // wait until transmission complete - timeout := i2cTimeout - for !i2c.Bus.INTFLAG.HasBits(sam.SERCOM_I2CM_INTFLAG_MB) { - timeout-- - if timeout == 0 { - return errI2CWriteTimeout - } - } - - // ACK received (0: ACK, 1: NACK) - if i2c.Bus.STATUS.HasBits(sam.SERCOM_I2CM_STATUS_RXNACK) { - return errI2CAckExpected - } - - // write data - for _, b := range w { - err = i2c.WriteByte(b) - if err != nil { - return err - } - } - - err = i2c.signalStop() - if err != nil { - return err - } - } - if len(r) != 0 { - // send start/address for read - i2c.sendAddress(addr, false) - - // wait transmission complete - for !i2c.Bus.INTFLAG.HasBits(sam.SERCOM_I2CM_INTFLAG_SB) { - // If the peripheral NACKS the address, the MB bit will be set. - // In that case, send a stop condition and return error. - if i2c.Bus.INTFLAG.HasBits(sam.SERCOM_I2CM_INTFLAG_MB) { - i2c.Bus.CTRLB.SetBits(wireCmdStop << sam.SERCOM_I2CM_CTRLB_CMD_Pos) // Stop condition - return errI2CAckExpected - } - } - - // ACK received (0: ACK, 1: NACK) - if i2c.Bus.STATUS.HasBits(sam.SERCOM_I2CM_STATUS_RXNACK) { - return errI2CAckExpected - } - - // read first byte - r[0] = i2c.readByte() - for i := 1; i < len(r); i++ { - // Send an ACK - i2c.Bus.CTRLB.ClearBits(sam.SERCOM_I2CM_CTRLB_ACKACT) - - i2c.signalRead() - - // Read data and send the ACK - r[i] = i2c.readByte() - } - - // Send NACK to end transmission - i2c.Bus.CTRLB.SetBits(sam.SERCOM_I2CM_CTRLB_ACKACT) - - err = i2c.signalStop() - if err != nil { - return err - } - } - - return nil -} - -// WriteByte writes a single byte to the I2C bus. -func (i2c *I2C) WriteByte(data byte) error { - // Send data byte - i2c.Bus.DATA.Set(data) - - // wait until transmission successful - timeout := i2cTimeout - for !i2c.Bus.INTFLAG.HasBits(sam.SERCOM_I2CM_INTFLAG_MB) { - // check for bus error - if sam.SERCOM3_I2CM.STATUS.HasBits(sam.SERCOM_I2CM_STATUS_BUSERR) { - return errI2CBusError - } - timeout-- - if timeout == 0 { - return errI2CWriteTimeout - } - } - - if i2c.Bus.STATUS.HasBits(sam.SERCOM_I2CM_STATUS_RXNACK) { - return errI2CAckExpected - } - - return nil -} - -// sendAddress sends the address and start signal -func (i2c *I2C) sendAddress(address uint16, write bool) error { - data := (address << 1) - if !write { - data |= 1 // set read flag - } - - // wait until bus ready - timeout := i2cTimeout - for !i2c.Bus.STATUS.HasBits(wireIdleState< 0 { - baudRate-- - } - spi.Bus.BAUD.Set(uint8(baudRate)) - - // Enable SPI port. - spi.Bus.CTRLA.SetBits(sam.SERCOM_SPI_CTRLA_ENABLE) - for spi.Bus.SYNCBUSY.HasBits(sam.SERCOM_SPI_SYNCBUSY_ENABLE) { - } - - return nil -} - -// Transfer writes/reads a single byte using the SPI interface. -func (spi *SPI) Transfer(w byte) (byte, error) { - // write data - spi.Bus.DATA.Set(uint32(w)) - - // wait for receive - for !spi.Bus.INTFLAG.HasBits(sam.SERCOM_SPI_INTFLAG_RXC) { - } - - // return data - return byte(spi.Bus.DATA.Get()), nil -} - -// Tx handles read/write operation for SPI interface. Since SPI is a synchronous write/read -// interface, there must always be the same number of bytes written as bytes read. -// The Tx method knows about this, and offers a few different ways of calling it. -// -// This form sends the bytes in tx buffer, putting the resulting bytes read into the rx buffer. -// Note that the tx and rx buffers must be the same size: -// -// spi.Tx(tx, rx) -// -// This form sends the tx buffer, ignoring the result. Useful for sending "commands" that return zeros -// until all the bytes in the command packet have been received: -// -// spi.Tx(tx, nil) -// -// This form sends zeros, putting the result into the rx buffer. Good for reading a "result packet": -// -// spi.Tx(nil, rx) -func (spi *SPI) Tx(w, r []byte) error { - switch { - case w == nil: - // read only, so write zero and read a result. - spi.rx(r) - case r == nil: - // write only - spi.tx(w) - - default: - // write/read - if len(w) != len(r) { - return ErrTxInvalidSliceSize - } - - spi.txrx(w, r) - } - - return nil -} - -func (spi *SPI) tx(tx []byte) { - for i := 0; i < len(tx); i++ { - for !spi.Bus.INTFLAG.HasBits(sam.SERCOM_SPI_INTFLAG_DRE) { - } - spi.Bus.DATA.Set(uint32(tx[i])) - } - for !spi.Bus.INTFLAG.HasBits(sam.SERCOM_SPI_INTFLAG_TXC) { - } - - // read to clear RXC register - for spi.Bus.INTFLAG.HasBits(sam.SERCOM_SPI_INTFLAG_RXC) { - spi.Bus.DATA.Get() - } -} - -func (spi *SPI) rx(rx []byte) { - spi.Bus.DATA.Set(0) - for !spi.Bus.INTFLAG.HasBits(sam.SERCOM_SPI_INTFLAG_DRE) { - } - - for i := 1; i < len(rx); i++ { - spi.Bus.DATA.Set(0) - for !spi.Bus.INTFLAG.HasBits(sam.SERCOM_SPI_INTFLAG_RXC) { - } - rx[i-1] = byte(spi.Bus.DATA.Get()) - } - for !spi.Bus.INTFLAG.HasBits(sam.SERCOM_SPI_INTFLAG_RXC) { - } - rx[len(rx)-1] = byte(spi.Bus.DATA.Get()) -} - -func (spi *SPI) txrx(tx, rx []byte) { - spi.Bus.DATA.Set(uint32(tx[0])) - for !spi.Bus.INTFLAG.HasBits(sam.SERCOM_SPI_INTFLAG_DRE) { - } - - for i := 1; i < len(rx); i++ { - spi.Bus.DATA.Set(uint32(tx[i])) - for !spi.Bus.INTFLAG.HasBits(sam.SERCOM_SPI_INTFLAG_RXC) { - } - rx[i-1] = byte(spi.Bus.DATA.Get()) - } - for !spi.Bus.INTFLAG.HasBits(sam.SERCOM_SPI_INTFLAG_RXC) { - } - rx[len(rx)-1] = byte(spi.Bus.DATA.Get()) -} - -// TCC is one timer/counter peripheral, which consists of a counter and multiple -// output channels (that can be connected to actual pins). You can set the -// frequency using SetPeriod, but only for all the channels in this TCC -// peripheral at once. -type TCC sam.TCC_Type - -// The SAM D21 has three TCC peripherals, which have PWM as one feature. -var ( - TCC0 = (*TCC)(sam.TCC0) - TCC1 = (*TCC)(sam.TCC1) - TCC2 = (*TCC)(sam.TCC2) -) - -//go:inline -func (tcc *TCC) timer() *sam.TCC_Type { - return (*sam.TCC_Type)(tcc) -} - -// Configure enables and configures this TCC. -func (tcc *TCC) Configure(config PWMConfig) error { - // Enable the clock source for this timer. - switch tcc.timer() { - case sam.TCC0: - sam.PM.APBCMASK.SetBits(sam.PM_APBCMASK_TCC0_) - // Use GCLK0 for TCC0/TCC1 - sam.GCLK.CLKCTRL.Set((sam.GCLK_CLKCTRL_ID_TCC0_TCC1 << sam.GCLK_CLKCTRL_ID_Pos) | - (sam.GCLK_CLKCTRL_GEN_GCLK0 << sam.GCLK_CLKCTRL_GEN_Pos) | - sam.GCLK_CLKCTRL_CLKEN) - for sam.GCLK.STATUS.HasBits(sam.GCLK_STATUS_SYNCBUSY) { - } - case sam.TCC1: - sam.PM.APBCMASK.SetBits(sam.PM_APBCMASK_TCC1_) - // Use GCLK0 for TCC0/TCC1 - sam.GCLK.CLKCTRL.Set((sam.GCLK_CLKCTRL_ID_TCC0_TCC1 << sam.GCLK_CLKCTRL_ID_Pos) | - (sam.GCLK_CLKCTRL_GEN_GCLK0 << sam.GCLK_CLKCTRL_GEN_Pos) | - sam.GCLK_CLKCTRL_CLKEN) - for sam.GCLK.STATUS.HasBits(sam.GCLK_STATUS_SYNCBUSY) { - } - case sam.TCC2: - sam.PM.APBCMASK.SetBits(sam.PM_APBCMASK_TCC2_) - // Use GCLK0 for TCC2/TC3 - sam.GCLK.CLKCTRL.Set((sam.GCLK_CLKCTRL_ID_TCC2_TC3 << sam.GCLK_CLKCTRL_ID_Pos) | - (sam.GCLK_CLKCTRL_GEN_GCLK0 << sam.GCLK_CLKCTRL_GEN_Pos) | - sam.GCLK_CLKCTRL_CLKEN) - for sam.GCLK.STATUS.HasBits(sam.GCLK_STATUS_SYNCBUSY) { - } - } - - // Disable timer (if it was enabled). This is necessary because - // tcc.setPeriod may want to change the prescaler bits in CTRLA, which is - // only allowed when the TCC is disabled. - tcc.timer().CTRLA.ClearBits(sam.TCC_CTRLA_ENABLE) - - // Use "Normal PWM" (single-slope PWM) - tcc.timer().WAVE.Set(sam.TCC_WAVE_WAVEGEN_NPWM) - - // Wait for synchronization of all changed registers. - for tcc.timer().SYNCBUSY.Get() != 0 { - } - - // Set the period and prescaler. - err := tcc.setPeriod(config.Period, true) - - // Enable the timer. - tcc.timer().CTRLA.SetBits(sam.TCC_CTRLA_ENABLE) - - // Wait for synchronization of all changed registers. - for tcc.timer().SYNCBUSY.Get() != 0 { - } - - // Return any error that might have occurred in the tcc.setPeriod call. - return err -} - -// SetPeriod updates the period of this TCC peripheral. -// To set a particular frequency, use the following formula: -// -// period = 1e9 / frequency -// -// If you use a period of 0, a period that works well for LEDs will be picked. -// -// SetPeriod will not change the prescaler, but also won't change the current -// value in any of the channels. This means that you may need to update the -// value for the particular channel. -// -// Note that you cannot pick any arbitrary period after the TCC peripheral has -// been configured. If you want to switch between frequencies, pick the lowest -// frequency (longest period) once when calling Configure and adjust the -// frequency here as needed. -func (tcc *TCC) SetPeriod(period uint64) error { - err := tcc.setPeriod(period, false) - if err == nil { - if tcc.Counter() >= tcc.Top() { - // When setting the timer to a shorter period, there is a chance - // that it passes the counter value and thus goes all the way to MAX - // before wrapping back to zero. - // To avoid this, reset the counter back to 0. - tcc.timer().COUNT.Set(0) - } - } - return err -} - -// setPeriod sets the period of this TCC, possibly updating the prescaler as -// well. The prescaler can only modified when the TCC is disabled, that is, in -// the Configure function. -func (tcc *TCC) setPeriod(period uint64, updatePrescaler bool) error { - var top uint64 - if period == 0 { - // Make sure the TOP value is at 0xffff (enough for a 16-bit timer). - top = 0xffff - } else { - // The formula below calculates the following formula, optimized: - // period * (48e6 / 1e9) - // This assumes that the chip is running at the (default) 48MHz speed. - top = period * 6 / 125 - } - - maxTop := uint64(0xffffff) - if tcc.timer() == sam.TCC2 { - // TCC2 is a 16-bit timer, not a 24-bit timer. - maxTop = 0xffff - } - - if updatePrescaler { - // This function was called during Configure(), with the timer disabled. - // Note that updating the prescaler can only happen while the peripheral - // is disabled. - var prescaler uint32 - switch { - case top <= maxTop: - prescaler = sam.TCC_CTRLA_PRESCALER_DIV1 - case top/2 <= maxTop: - prescaler = sam.TCC_CTRLA_PRESCALER_DIV2 - top = top / 2 - case top/4 <= maxTop: - prescaler = sam.TCC_CTRLA_PRESCALER_DIV4 - top = top / 4 - case top/8 <= maxTop: - prescaler = sam.TCC_CTRLA_PRESCALER_DIV8 - top = top / 8 - case top/16 <= maxTop: - prescaler = sam.TCC_CTRLA_PRESCALER_DIV16 - top = top / 16 - case top/64 <= maxTop: - prescaler = sam.TCC_CTRLA_PRESCALER_DIV64 - top = top / 64 - case top/256 <= maxTop: - prescaler = sam.TCC_CTRLA_PRESCALER_DIV256 - top = top / 256 - case top/1024 <= maxTop: - prescaler = sam.TCC_CTRLA_PRESCALER_DIV1024 - top = top / 1024 - default: - return ErrPWMPeriodTooLong - } - tcc.timer().CTRLA.Set((tcc.timer().CTRLA.Get() &^ sam.TCC_CTRLA_PRESCALER_Msk) | (prescaler << sam.TCC_CTRLA_PRESCALER_Pos)) - } else { - // Do not update the prescaler, but use the already-configured - // prescaler. This is the normal SetPeriod case, where the prescaler - // must not be changed. - prescaler := (tcc.timer().CTRLA.Get() & sam.TCC_CTRLA_PRESCALER_Msk) >> sam.TCC_CTRLA_PRESCALER_Pos - switch prescaler { - case sam.TCC_CTRLA_PRESCALER_DIV1: - top /= 1 // no-op - case sam.TCC_CTRLA_PRESCALER_DIV2: - top /= 2 - case sam.TCC_CTRLA_PRESCALER_DIV4: - top /= 4 - case sam.TCC_CTRLA_PRESCALER_DIV8: - top /= 8 - case sam.TCC_CTRLA_PRESCALER_DIV16: - top /= 16 - case sam.TCC_CTRLA_PRESCALER_DIV64: - top /= 64 - case sam.TCC_CTRLA_PRESCALER_DIV256: - top /= 256 - case sam.TCC_CTRLA_PRESCALER_DIV1024: - top /= 1024 - default: - // unreachable - } - if top > maxTop { - return ErrPWMPeriodTooLong - } - } - - // Set the period (the counter top). - tcc.timer().PER.Set(uint32(top) - 1) - - // Wait for synchronization of CTRLA.PRESCALER and PER registers. - for tcc.timer().SYNCBUSY.Get() != 0 { - } - - return nil -} - -// Top returns the current counter top, for use in duty cycle calculation. It -// will only change with a call to Configure or SetPeriod, otherwise it is -// constant. -// -// The value returned here is hardware dependent. In general, it's best to treat -// it as an opaque value that can be divided by some number and passed to Set -// (see Set documentation for more information). -func (tcc *TCC) Top() uint32 { - return tcc.timer().PER.Get() + 1 -} - -// Counter returns the current counter value of the timer in this TCC -// peripheral. It may be useful for debugging. -func (tcc *TCC) Counter() uint32 { - tcc.timer().CTRLBSET.Set(sam.TCC_CTRLBSET_CMD_READSYNC << sam.TCC_CTRLBSET_CMD_Pos) - for tcc.timer().SYNCBUSY.Get() != 0 { - } - return tcc.timer().COUNT.Get() -} - -// Some constants to make pinTimerMapping below easier to read. -const ( - pinTCC0 = 1 - pinTCC1 = 2 - pinTCC2 = 3 - pinTimerCh0 = 0 << 3 - pinTimerCh2 = 1 << 3 - pinTCC0Ch0 = pinTCC0 | pinTimerCh0 - pinTCC0Ch2 = pinTCC0 | pinTimerCh2 - pinTCC1Ch0 = pinTCC1 | pinTimerCh0 - pinTCC1Ch2 = pinTCC1 | pinTimerCh2 - pinTCC2Ch0 = pinTCC2 | pinTimerCh0 -) - -// Mapping from pin number to TCC peripheral and channel using a special -// encoding. Note that only TCC0-TCC2 are included, not TC3 and up. -// Every byte is split in two nibbles where the low nibble describes PinTCC and -// the high nibble describes PinTCCAlt. Within a nibble, there is one bit that -// indicates Ch0/Ch1 or Ch2/Ch3, and three other bits that contain the TCC -// peripheral number plus one (to distinguish between TCC0Ch0 and 0). -// -// The encoding can be so compact because all pins are configured in pairs, so -// if you know PA00 you can infer the configuration of PA01. And only channel 0 -// or 2 need to be included (taking up just one bit), because channel 0 and 2 -// are only ever used on odd pins and channel 1 and 3 on even pins, again using -// the pin pair pattern to reduce the amount of information needed to be stored. -// -// Datasheet: https://cdn.sparkfun.com/datasheets/Dev/Arduino/Boards/Atmel-42181-SAM-D21_Datasheet.pdf -var pinTimerMapping = [...]uint8{ - // page 21 - PA00 / 2: pinTCC2Ch0 | 0, - PA04 / 2: pinTCC0Ch0 | 0, - PA06 / 2: pinTCC1Ch0 | 0, - PA08 / 2: pinTCC0Ch0 | pinTCC1Ch2<<4, - PA10 / 2: pinTCC1Ch0 | pinTCC0Ch2<<4, - // page 22 - PB10 / 2: 0 | pinTCC0Ch0<<4, - PB12 / 2: 0 | pinTCC0Ch2<<4, - PA12 / 2: pinTCC2Ch0 | pinTCC0Ch2<<4, - PA14 / 2: 0 | pinTCC0Ch0<<4, - PA16 / 2: pinTCC2Ch0 | pinTCC0Ch2<<4, - PA18 / 2: 0 | pinTCC0Ch2<<4, - PB16 / 2: 0 | pinTCC0Ch0<<4, - PA20 / 2: 0 | pinTCC0Ch2<<4, - PA22 / 2: 0 | pinTCC0Ch0<<4, - PA24 / 2: 0 | pinTCC1Ch2<<4, - // page 23 - PA30 / 2: 0 | pinTCC1Ch0<<4, - PB30 / 2: pinTCC0Ch0 | pinTCC1Ch2<<4, -} - -// findPinTimerMapping returns the pin mode (PinTCC or PinTCCAlt) and the channel -// number for a given timer and pin. A zero PinMode is returned if no mapping -// could be found. -func findPinTimerMapping(timer uint8, pin Pin) (PinMode, uint8) { - mapping := pinTimerMapping[pin/2] - // evenChannel below indicates the channel 0 or 2, for the even part of the - // pin pair. The next pin will also have the next channel (1 or 3). - if mapping&0x07 == timer+1 { - // PWM output is on peripheral function E. - evenChannel := ((mapping >> 3) & 1) * 2 - return PinTCC, evenChannel + uint8(pin&1) - } - if (mapping&0x70)>>4 == timer+1 { - // PWM output is on peripheral function F. - evenChannel := ((mapping >> 7) & 1) * 2 - return PinTCCAlt, evenChannel + uint8(pin&1) - } - return 0, 0 -} - -// Channel returns a PWM channel for the given pin. Note that one channel may be -// shared between multiple pins, and so will have the same duty cycle. If this -// is not desirable, look for a different TCC peripheral or consider using a -// different pin. -func (tcc *TCC) Channel(pin Pin) (uint8, error) { - var pinMode PinMode - var channel uint8 - switch tcc.timer() { - case sam.TCC0: - pinMode, channel = findPinTimerMapping(0, pin) - case sam.TCC1: - pinMode, channel = findPinTimerMapping(1, pin) - case sam.TCC2: - pinMode, channel = findPinTimerMapping(2, pin) - } - - if pinMode == 0 { - // No pin could be found. - return 0, ErrInvalidOutputPin - } - - // Enable the port multiplexer for pin - pin.setPinCfg(sam.PORT_PINCFG0_PMUXEN) - - if pin&1 > 0 { - // odd pin, so save the even pins - val := pin.getPMux() & sam.PORT_PMUX0_PMUXE_Msk - pin.setPMux(val | uint8(pinMode<> 6) - syncDAC() - return nil -} - -func syncDAC() { - for sam.DAC.STATUS.HasBits(sam.DAC_STATUS_SYNCBUSY) { - } -} - -// Flash related code -const memoryStart = 0x0 - -// compile-time check for ensuring we fulfill BlockDevice interface -var _ BlockDevice = flashBlockDevice{} - -var Flash flashBlockDevice - -type flashBlockDevice struct { - initComplete bool -} - -// ReadAt reads the given number of bytes from the block device. -func (f flashBlockDevice) ReadAt(p []byte, off int64) (n int, err error) { - if FlashDataStart()+uintptr(off)+uintptr(len(p)) > FlashDataEnd() { - return 0, errFlashCannotReadPastEOF - } - - f.ensureInitComplete() - - waitWhileFlashBusy() - - data := unsafe.Slice((*byte)(unsafe.Add(unsafe.Pointer(FlashDataStart()), uintptr(off))), len(p)) - copy(p, data) - - return len(p), nil -} - -// WriteAt writes the given number of bytes to the block device. -// Data is written to the page buffer in 4-byte chunks, then saved to flash memory. -// See Atmel-42181G–SAM-D21_Datasheet–09/2015 page 359. -// If the length of p is not long enough it will be padded with 0xFF bytes. -// This method assumes that the destination is already erased. -func (f flashBlockDevice) WriteAt(p []byte, off int64) (n int, err error) { - if FlashDataStart()+uintptr(off)+uintptr(len(p)) > FlashDataEnd() { - return 0, errFlashCannotWritePastEOF - } - - f.ensureInitComplete() - - address := FlashDataStart() + uintptr(off) - padded := flashPad(p, int(f.WriteBlockSize())) - - waitWhileFlashBusy() - - for j := 0; j < len(padded); j += int(f.WriteBlockSize()) { - // page buffer is 64 bytes long, but only 4 bytes can be written at once - for k := 0; k < int(f.WriteBlockSize()); k += 4 { - *(*uint32)(unsafe.Pointer(address + uintptr(k))) = binary.LittleEndian.Uint32(padded[j+k : j+k+4]) - } - - sam.NVMCTRL.SetADDR(uint32(address >> 1)) - sam.NVMCTRL.CTRLA.Set(sam.NVMCTRL_CTRLA_CMD_WP | (sam.NVMCTRL_CTRLA_CMDEX_KEY << sam.NVMCTRL_CTRLA_CMDEX_Pos)) - - waitWhileFlashBusy() - - if err := checkFlashError(); err != nil { - return j, err - } - - address += uintptr(f.WriteBlockSize()) - } - - return len(padded), nil -} - -// Size returns the number of bytes in this block device. -func (f flashBlockDevice) Size() int64 { - return int64(FlashDataEnd() - FlashDataStart()) -} - -const writeBlockSize = 64 - -// WriteBlockSize returns the block size in which data can be written to -// memory. It can be used by a client to optimize writes, non-aligned writes -// should always work correctly. -func (f flashBlockDevice) WriteBlockSize() int64 { - return writeBlockSize -} - -const eraseBlockSizeValue = 256 - -func eraseBlockSize() int64 { - return eraseBlockSizeValue -} - -// EraseBlockSize returns the smallest erasable area on this particular chip -// in bytes. This is used for the block size in EraseBlocks. -func (f flashBlockDevice) EraseBlockSize() int64 { - return eraseBlockSize() -} - -// EraseBlocks erases the given number of blocks. An implementation may -// transparently coalesce ranges of blocks into larger bundles if the chip -// supports this. The start and len parameters are in block numbers, use -// EraseBlockSize to map addresses to blocks. -func (f flashBlockDevice) EraseBlocks(start, len int64) error { - f.ensureInitComplete() - - address := FlashDataStart() + uintptr(start*f.EraseBlockSize()) - waitWhileFlashBusy() - - for i := start; i < start+len; i++ { - sam.NVMCTRL.SetADDR(uint32(address >> 1)) - sam.NVMCTRL.CTRLA.Set(sam.NVMCTRL_CTRLA_CMD_ER | (sam.NVMCTRL_CTRLA_CMDEX_KEY << sam.NVMCTRL_CTRLA_CMDEX_Pos)) - - waitWhileFlashBusy() - - if err := checkFlashError(); err != nil { - return err - } - - address += uintptr(f.EraseBlockSize()) - } - - return nil -} - -func (f flashBlockDevice) ensureInitComplete() { - if f.initComplete { - return - } - - sam.NVMCTRL.SetCTRLB_READMODE(sam.NVMCTRL_CTRLB_READMODE_NO_MISS_PENALTY) - sam.NVMCTRL.SetCTRLB_SLEEPPRM(sam.NVMCTRL_CTRLB_SLEEPPRM_WAKEONACCESS) - - waitWhileFlashBusy() - - f.initComplete = true -} - -func waitWhileFlashBusy() { - for sam.NVMCTRL.GetINTFLAG_READY() != sam.NVMCTRL_INTFLAG_READY { - } -} - -var ( - errFlashPROGE = errors.New("errFlashPROGE") - errFlashLOCKE = errors.New("errFlashLOCKE") - errFlashNVME = errors.New("errFlashNVME") -) - -func checkFlashError() error { - switch { - case sam.NVMCTRL.GetSTATUS_PROGE() != 0: - return errFlashPROGE - case sam.NVMCTRL.GetSTATUS_LOCKE() != 0: - return errFlashLOCKE - case sam.NVMCTRL.GetSTATUS_NVME() != 0: - return errFlashNVME - } - - return nil -} - -// Watchdog provides access to the hardware watchdog available -// in the SAMD21. -var Watchdog = &watchdogImpl{} - -const ( - // WatchdogMaxTimeout in milliseconds (16s) - WatchdogMaxTimeout = (16384 * 1000) / 1024 -) - -type watchdogImpl struct{} - -// Configure the watchdog. -// -// This method should not be called after the watchdog is started and on -// some platforms attempting to reconfigure after starting the watchdog -// is explicitly forbidden / will not work. -func (wd *watchdogImpl) Configure(config WatchdogConfig) error { - // Use OSCULP32K as source for Generic Clock Generator 8, divided by 32 to get 1.024kHz - sam.GCLK.GENDIV.Set(sam.GCLK_CLKCTRL_GEN_GCLK8 | (32 << sam.GCLK_GENDIV_DIV_Pos)) - sam.GCLK.GENCTRL.Set(sam.GCLK_CLKCTRL_GEN_GCLK8 | (sam.GCLK_GENCTRL_SRC_OSCULP32K << sam.GCLK_GENCTRL_SRC_Pos) | sam.GCLK_GENCTRL_GENEN) - waitForSync() - - // Use GCLK8 for watchdog - sam.GCLK.CLKCTRL.Set(sam.GCLK_CLKCTRL_ID_WDT | (sam.GCLK_CLKCTRL_GEN_GCLK8 << sam.GCLK_CLKCTRL_GEN_Pos) | sam.GCLK_CLKCTRL_CLKEN) - - // Power on the watchdog peripheral - sam.PM.APBAMASK.SetBits(sam.PM_APBAMASK_WDT_) - - // 1.024kHz clock - cycles := int((int64(config.TimeoutMillis) * 1024) / 1000) - - // period is expressed as a power-of-two, starting at 8 / 1024ths of a second - period := uint8(0) - cfgCycles := 8 - for cfgCycles < cycles { - period++ - cfgCycles <<= 1 - - if period >= 0xB { - break - } - } - - sam.WDT.CONFIG.Set(period << sam.WDT_CONFIG_PER_Pos) - - return nil -} - -// Starts the watchdog. -func (wd *watchdogImpl) Start() error { - sam.WDT.CTRL.SetBits(sam.WDT_CTRL_ENABLE) - return nil -} - -// Update the watchdog, indicating that `source` is healthy. -func (wd *watchdogImpl) Update() { - sam.WDT.CLEAR.Set(sam.WDT_CLEAR_CLEAR_KEY) -} diff --git a/emb/machine/machine_atsamd21_simulator.go b/emb/machine/machine_atsamd21_simulator.go deleted file mode 100644 index 2a22533..0000000 --- a/emb/machine/machine_atsamd21_simulator.go +++ /dev/null @@ -1,45 +0,0 @@ -//go:build !baremetal && (gemma_m0 || qtpy || trinket_m0 || arduino_mkr1000 || arduino_mkrwifi1010 || arduino_nano33 || arduino_zero || circuitplay_express || feather_m0_express || feather_m0 || itsybitsy_m0 || p1am_100 || xiao) - -// Simulated atsamd21 chips. - -package machine - -// The timer channels/pins match the hardware, and encode the same information -// as pinTimerMapping but in a more generic (less efficient) way. - -var TCC0 = &timerType{ - instance: 0, - frequency: 48e6, - bits: 24, - prescalers: []int{1, 2, 4, 8, 16, 64, 256, 1024}, - channelPins: [][]Pin{ - {PA04, PA08, PB10, PA14, PB16, PA22, PB30}, // channel 0 - {PA05, PA09, PB11, PA15, PB17, PA23, PB31}, // channel 1 - {PA10, PB12, PA12, PA16, PA18, PA20}, // channel 2 - {PA11, PB13, PA13, PA17, PA19, PA21}, // channel 3 - }, -} - -var TCC1 = &timerType{ - instance: 1, - frequency: 48e6, - bits: 24, - prescalers: []int{1, 2, 4, 8, 16, 64, 256, 1024}, - channelPins: [][]Pin{ - {PA06, PA10, PA30}, // channel 0 - {PA07, PA11, PA31}, // channel 1 - {PA08, PA24, PB30}, // channel 2 - {PA09, PA25, PB31}, // channel 3 - }, -} - -var TCC2 = &timerType{ - instance: 2, - frequency: 48e6, - bits: 16, - prescalers: []int{1, 2, 4, 8, 16, 64, 256, 1024}, - channelPins: [][]Pin{ - {PA00, PA12, PA16}, // channel 0 - {PA01, PA13, PA17}, // channel 1 - }, -} diff --git a/emb/machine/machine_atsamd21_usb.go b/emb/machine/machine_atsamd21_usb.go deleted file mode 100644 index 7b9d2e1..0000000 --- a/emb/machine/machine_atsamd21_usb.go +++ /dev/null @@ -1,664 +0,0 @@ -//go:build sam && atsamd21 - -package machine - -import ( - "device/sam" - "machine/usb" - "runtime/interrupt" - "unsafe" -) - -const ( - // these are SAMD21 specific. - usb_DEVICE_PCKSIZE_BYTE_COUNT_Pos = 0 - usb_DEVICE_PCKSIZE_BYTE_COUNT_Mask = 0x3FFF - - usb_DEVICE_PCKSIZE_SIZE_Pos = 28 - usb_DEVICE_PCKSIZE_SIZE_Mask = 0x7 - - usb_DEVICE_PCKSIZE_MULTI_PACKET_SIZE_Pos = 14 - usb_DEVICE_PCKSIZE_MULTI_PACKET_SIZE_Mask = 0x3FFF - - NumberOfUSBEndpoints = 8 -) - -var ( - endPoints = []uint32{ - usb.CONTROL_ENDPOINT: usb.ENDPOINT_TYPE_CONTROL, - usb.CDC_ENDPOINT_ACM: (usb.ENDPOINT_TYPE_INTERRUPT | usb.EndpointIn), - usb.CDC_ENDPOINT_OUT: (usb.ENDPOINT_TYPE_BULK | usb.EndpointOut), - usb.CDC_ENDPOINT_IN: (usb.ENDPOINT_TYPE_BULK | usb.EndpointIn), - usb.HID_ENDPOINT_IN: (usb.ENDPOINT_TYPE_DISABLE), // Interrupt In - usb.HID_ENDPOINT_OUT: (usb.ENDPOINT_TYPE_DISABLE), // Interrupt Out - usb.MIDI_ENDPOINT_IN: (usb.ENDPOINT_TYPE_DISABLE), // Bulk In - usb.MIDI_ENDPOINT_OUT: (usb.ENDPOINT_TYPE_DISABLE), // Bulk Out - } -) - -// Configure the USB peripheral. The config is here for compatibility with the UART interface. -func (dev *USBDevice) Configure(config UARTConfig) { - if dev.initcomplete { - return - } - - // reset USB interface - sam.USB_DEVICE.CTRLA.SetBits(sam.USB_DEVICE_CTRLA_SWRST) - for sam.USB_DEVICE.SYNCBUSY.HasBits(sam.USB_DEVICE_SYNCBUSY_SWRST) || - sam.USB_DEVICE.SYNCBUSY.HasBits(sam.USB_DEVICE_SYNCBUSY_ENABLE) { - } - - sam.USB_DEVICE.DESCADD.Set(uint32(uintptr(unsafe.Pointer(&usbEndpointDescriptors)))) - - // configure pins - USBCDC_DM_PIN.Configure(PinConfig{Mode: PinCom}) - USBCDC_DP_PIN.Configure(PinConfig{Mode: PinCom}) - - // performs pad calibration from store fuses - handlePadCalibration() - - // run in standby - sam.USB_DEVICE.CTRLA.SetBits(sam.USB_DEVICE_CTRLA_RUNSTDBY) - - // set full speed - sam.USB_DEVICE.CTRLB.SetBits(sam.USB_DEVICE_CTRLB_SPDCONF_FS << sam.USB_DEVICE_CTRLB_SPDCONF_Pos) - - // attach - sam.USB_DEVICE.CTRLB.ClearBits(sam.USB_DEVICE_CTRLB_DETACH) - - // enable interrupt for end of reset - sam.USB_DEVICE.INTENSET.SetBits(sam.USB_DEVICE_INTENSET_EORST) - - // enable interrupt for start of frame - sam.USB_DEVICE.INTENSET.SetBits(sam.USB_DEVICE_INTENSET_SOF) - - // enable USB - sam.USB_DEVICE.CTRLA.SetBits(sam.USB_DEVICE_CTRLA_ENABLE) - - // enable IRQ - interrupt.New(sam.IRQ_USB, handleUSBIRQ).Enable() - - dev.initcomplete = true -} - -func handlePadCalibration() { - // Load Pad Calibration data from non-volatile memory - // This requires registers that are not included in the SVD file. - // Modeled after defines from samd21g18a.h and nvmctrl.h: - // - // #define NVMCTRL_OTP4 0x00806020 - // - // #define USB_FUSES_TRANSN_ADDR (NVMCTRL_OTP4 + 4) - // #define USB_FUSES_TRANSN_Pos 13 /**< \brief (NVMCTRL_OTP4) USB pad Transn calibration */ - // #define USB_FUSES_TRANSN_Msk (0x1Fu << USB_FUSES_TRANSN_Pos) - // #define USB_FUSES_TRANSN(value) ((USB_FUSES_TRANSN_Msk & ((value) << USB_FUSES_TRANSN_Pos))) - - // #define USB_FUSES_TRANSP_ADDR (NVMCTRL_OTP4 + 4) - // #define USB_FUSES_TRANSP_Pos 18 /**< \brief (NVMCTRL_OTP4) USB pad Transp calibration */ - // #define USB_FUSES_TRANSP_Msk (0x1Fu << USB_FUSES_TRANSP_Pos) - // #define USB_FUSES_TRANSP(value) ((USB_FUSES_TRANSP_Msk & ((value) << USB_FUSES_TRANSP_Pos))) - - // #define USB_FUSES_TRIM_ADDR (NVMCTRL_OTP4 + 4) - // #define USB_FUSES_TRIM_Pos 23 /**< \brief (NVMCTRL_OTP4) USB pad Trim calibration */ - // #define USB_FUSES_TRIM_Msk (0x7u << USB_FUSES_TRIM_Pos) - // #define USB_FUSES_TRIM(value) ((USB_FUSES_TRIM_Msk & ((value) << USB_FUSES_TRIM_Pos))) - // - fuse := *(*uint32)(unsafe.Pointer(uintptr(0x00806020) + 4)) - calibTransN := uint16(fuse>>13) & uint16(0x1f) - calibTransP := uint16(fuse>>18) & uint16(0x1f) - calibTrim := uint16(fuse>>23) & uint16(0x7) - - if calibTransN == 0x1f { - calibTransN = 5 - } - sam.USB_DEVICE.PADCAL.SetBits(calibTransN << sam.USB_DEVICE_PADCAL_TRANSN_Pos) - - if calibTransP == 0x1f { - calibTransP = 29 - } - sam.USB_DEVICE.PADCAL.SetBits(calibTransP << sam.USB_DEVICE_PADCAL_TRANSP_Pos) - - if calibTrim == 0x7 { - calibTrim = 3 - } - sam.USB_DEVICE.PADCAL.SetBits(calibTrim << sam.USB_DEVICE_PADCAL_TRIM_Pos) -} - -func handleUSBIRQ(intr interrupt.Interrupt) { - // reset all interrupt flags - flags := sam.USB_DEVICE.INTFLAG.Get() - sam.USB_DEVICE.INTFLAG.Set(flags) - - // End of reset - if (flags & sam.USB_DEVICE_INTFLAG_EORST) > 0 { - // Configure control endpoint - initEndpoint(0, usb.ENDPOINT_TYPE_CONTROL) - - usbConfiguration = 0 - - // ack the End-Of-Reset interrupt - sam.USB_DEVICE.INTFLAG.Set(sam.USB_DEVICE_INTFLAG_EORST) - } - - // Start of frame - if (flags & sam.USB_DEVICE_INTFLAG_SOF) > 0 { - // if you want to blink LED showing traffic, this would be the place... - } - - // Endpoint 0 Setup interrupt - if getEPINTFLAG(0)&sam.USB_DEVICE_EPINTFLAG_RXSTP > 0 { - // ack setup received - setEPINTFLAG(0, sam.USB_DEVICE_EPINTFLAG_RXSTP) - - // parse setup - setup := usb.NewSetup(udd_ep_out_cache_buffer[0][:]) - - // Clear the Bank 0 ready flag on Control OUT - usbEndpointDescriptors[0].DeviceDescBank[0].ADDR.Set(uint32(uintptr(unsafe.Pointer(&udd_ep_out_cache_buffer[0])))) - usbEndpointDescriptors[0].DeviceDescBank[0].PCKSIZE.ClearBits(usb_DEVICE_PCKSIZE_BYTE_COUNT_Mask << usb_DEVICE_PCKSIZE_BYTE_COUNT_Pos) - setEPSTATUSCLR(0, sam.USB_DEVICE_EPSTATUSCLR_BK0RDY) - - ok := false - if (setup.BmRequestType & usb.REQUEST_TYPE) == usb.REQUEST_STANDARD { - // Standard Requests - ok = handleStandardSetup(setup) - } else { - // Class Interface Requests - if setup.WIndex < uint16(len(usbSetupHandler)) && usbSetupHandler[setup.WIndex] != nil { - ok = usbSetupHandler[setup.WIndex](setup) - } - } - - if ok { - // set Bank1 ready - setEPSTATUSSET(0, sam.USB_DEVICE_EPSTATUSSET_BK1RDY) - } else { - // Stall endpoint - setEPSTATUSSET(0, sam.USB_DEVICE_EPINTFLAG_STALL1) - } - - if getEPINTFLAG(0)&sam.USB_DEVICE_EPINTFLAG_STALL1 > 0 { - // ack the stall - setEPINTFLAG(0, sam.USB_DEVICE_EPINTFLAG_STALL1) - - // clear stall request - setEPINTENCLR(0, sam.USB_DEVICE_EPINTENCLR_STALL1) - } - } - - // Now the actual transfer handlers, ignore endpoint number 0 (setup) - var i uint32 - for i = 1; i < uint32(len(endPoints)); i++ { - // Check if endpoint has a pending interrupt - epFlags := getEPINTFLAG(i) - setEPINTFLAG(i, epFlags) - if (epFlags & sam.USB_DEVICE_EPINTFLAG_TRCPT0) > 0 { - buf := handleEndpointRx(i) - if usbRxHandler[i] == nil || usbRxHandler[i](buf) { - AckUsbOutTransfer(i) - } - } else if (epFlags & sam.USB_DEVICE_EPINTFLAG_TRCPT1) > 0 { - if usbTxHandler[i] != nil { - usbTxHandler[i]() - } - } - } -} - -func initEndpoint(ep, config uint32) { - switch config { - case usb.ENDPOINT_TYPE_INTERRUPT | usb.EndpointIn: - // set packet size - usbEndpointDescriptors[ep].DeviceDescBank[1].PCKSIZE.SetBits(epPacketSize(64) << usb_DEVICE_PCKSIZE_SIZE_Pos) - - // set data buffer address - usbEndpointDescriptors[ep].DeviceDescBank[1].ADDR.Set(uint32(uintptr(unsafe.Pointer(&udd_ep_in_cache_buffer[ep])))) - - // set endpoint type - setEPCFG(ep, ((usb.ENDPOINT_TYPE_INTERRUPT + 1) << sam.USB_DEVICE_EPCFG_EPTYPE1_Pos)) - - setEPINTENSET(ep, sam.USB_DEVICE_EPINTENSET_TRCPT1) - - case usb.ENDPOINT_TYPE_BULK | usb.EndpointOut: - // set packet size - usbEndpointDescriptors[ep].DeviceDescBank[0].PCKSIZE.SetBits(epPacketSize(64) << usb_DEVICE_PCKSIZE_SIZE_Pos) - - // set data buffer address - usbEndpointDescriptors[ep].DeviceDescBank[0].ADDR.Set(uint32(uintptr(unsafe.Pointer(&udd_ep_out_cache_buffer[ep])))) - - // set endpoint type - setEPCFG(ep, ((usb.ENDPOINT_TYPE_BULK + 1) << sam.USB_DEVICE_EPCFG_EPTYPE0_Pos)) - - // receive interrupts when current transfer complete - setEPINTENSET(ep, sam.USB_DEVICE_EPINTENSET_TRCPT0) - - // set byte count to zero, we have not received anything yet - usbEndpointDescriptors[ep].DeviceDescBank[0].PCKSIZE.ClearBits(usb_DEVICE_PCKSIZE_BYTE_COUNT_Mask << usb_DEVICE_PCKSIZE_BYTE_COUNT_Pos) - - // ready for next transfer - setEPSTATUSCLR(ep, sam.USB_DEVICE_EPSTATUSCLR_BK0RDY) - - case usb.ENDPOINT_TYPE_INTERRUPT | usb.EndpointOut: - // set packet size - usbEndpointDescriptors[ep].DeviceDescBank[0].PCKSIZE.SetBits(epPacketSize(64) << usb_DEVICE_PCKSIZE_SIZE_Pos) - - // set data buffer address - usbEndpointDescriptors[ep].DeviceDescBank[0].ADDR.Set(uint32(uintptr(unsafe.Pointer(&udd_ep_out_cache_buffer[ep])))) - - // set endpoint type - setEPCFG(ep, ((usb.ENDPOINT_TYPE_INTERRUPT + 1) << sam.USB_DEVICE_EPCFG_EPTYPE0_Pos)) - - // receive interrupts when current transfer complete - setEPINTENSET(ep, sam.USB_DEVICE_EPINTENSET_TRCPT0) - - // set byte count to zero, we have not received anything yet - usbEndpointDescriptors[ep].DeviceDescBank[0].PCKSIZE.ClearBits(usb_DEVICE_PCKSIZE_BYTE_COUNT_Mask << usb_DEVICE_PCKSIZE_BYTE_COUNT_Pos) - - // ready for next transfer - setEPSTATUSCLR(ep, sam.USB_DEVICE_EPSTATUSCLR_BK0RDY) - - case usb.ENDPOINT_TYPE_BULK | usb.EndpointIn: - // set packet size - usbEndpointDescriptors[ep].DeviceDescBank[1].PCKSIZE.SetBits(epPacketSize(64) << usb_DEVICE_PCKSIZE_SIZE_Pos) - - // set data buffer address - usbEndpointDescriptors[ep].DeviceDescBank[1].ADDR.Set(uint32(uintptr(unsafe.Pointer(&udd_ep_in_cache_buffer[ep])))) - - // set endpoint type - setEPCFG(ep, ((usb.ENDPOINT_TYPE_BULK + 1) << sam.USB_DEVICE_EPCFG_EPTYPE1_Pos)) - - // NAK on endpoint IN, the bank is not yet filled in. - setEPSTATUSCLR(ep, sam.USB_DEVICE_EPSTATUSCLR_BK1RDY) - - setEPINTENSET(ep, sam.USB_DEVICE_EPINTENSET_TRCPT1) - - case usb.ENDPOINT_TYPE_CONTROL: - // Control OUT - // set packet size - usbEndpointDescriptors[ep].DeviceDescBank[0].PCKSIZE.SetBits(epPacketSize(64) << usb_DEVICE_PCKSIZE_SIZE_Pos) - - // set data buffer address - usbEndpointDescriptors[ep].DeviceDescBank[0].ADDR.Set(uint32(uintptr(unsafe.Pointer(&udd_ep_out_cache_buffer[ep])))) - - // set endpoint type - setEPCFG(ep, getEPCFG(ep)|((usb.ENDPOINT_TYPE_CONTROL+1)<> - usb_DEVICE_PCKSIZE_BYTE_COUNT_Pos) & usb_DEVICE_PCKSIZE_BYTE_COUNT_Mask) - - if bytesread != cdcLineInfoSize { - return b, ErrUSBBytesRead - } - - copy(b[:7], udd_ep_out_cache_buffer[0][:7]) - - return b, nil -} - -func handleEndpointRx(ep uint32) []byte { - // get data - count := int((usbEndpointDescriptors[ep].DeviceDescBank[0].PCKSIZE.Get() >> - usb_DEVICE_PCKSIZE_BYTE_COUNT_Pos) & usb_DEVICE_PCKSIZE_BYTE_COUNT_Mask) - - return udd_ep_out_cache_buffer[ep][:count] -} - -// AckUsbOutTransfer is called to acknowledge the completion of a USB OUT transfer. -func AckUsbOutTransfer(ep uint32) { - // set byte count to zero - usbEndpointDescriptors[ep].DeviceDescBank[0].PCKSIZE.ClearBits(usb_DEVICE_PCKSIZE_BYTE_COUNT_Mask << usb_DEVICE_PCKSIZE_BYTE_COUNT_Pos) - - // set multi packet size to 64 - usbEndpointDescriptors[ep].DeviceDescBank[0].PCKSIZE.SetBits(64 << usb_DEVICE_PCKSIZE_MULTI_PACKET_SIZE_Pos) - - // set ready for next data - setEPSTATUSCLR(ep, sam.USB_DEVICE_EPSTATUSCLR_BK0RDY) - -} - -func SendZlp() { - usbEndpointDescriptors[0].DeviceDescBank[1].PCKSIZE.ClearBits(usb_DEVICE_PCKSIZE_BYTE_COUNT_Mask << usb_DEVICE_PCKSIZE_BYTE_COUNT_Pos) -} - -func epPacketSize(size uint16) uint32 { - switch size { - case 8: - return 0 - case 16: - return 1 - case 32: - return 2 - case 64: - return 3 - case 128: - return 4 - case 256: - return 5 - case 512: - return 6 - case 1023: - return 7 - default: - return 0 - } -} - -func getEPCFG(ep uint32) uint8 { - switch ep { - case 0: - return sam.USB_DEVICE.EPCFG0.Get() - case 1: - return sam.USB_DEVICE.EPCFG1.Get() - case 2: - return sam.USB_DEVICE.EPCFG2.Get() - case 3: - return sam.USB_DEVICE.EPCFG3.Get() - case 4: - return sam.USB_DEVICE.EPCFG4.Get() - case 5: - return sam.USB_DEVICE.EPCFG5.Get() - case 6: - return sam.USB_DEVICE.EPCFG6.Get() - case 7: - return sam.USB_DEVICE.EPCFG7.Get() - default: - return 0 - } -} - -func setEPCFG(ep uint32, val uint8) { - switch ep { - case 0: - sam.USB_DEVICE.EPCFG0.Set(val) - case 1: - sam.USB_DEVICE.EPCFG1.Set(val) - case 2: - sam.USB_DEVICE.EPCFG2.Set(val) - case 3: - sam.USB_DEVICE.EPCFG3.Set(val) - case 4: - sam.USB_DEVICE.EPCFG4.Set(val) - case 5: - sam.USB_DEVICE.EPCFG5.Set(val) - case 6: - sam.USB_DEVICE.EPCFG6.Set(val) - case 7: - sam.USB_DEVICE.EPCFG7.Set(val) - default: - return - } -} - -func setEPSTATUSCLR(ep uint32, val uint8) { - switch ep { - case 0: - sam.USB_DEVICE.EPSTATUSCLR0.Set(val) - case 1: - sam.USB_DEVICE.EPSTATUSCLR1.Set(val) - case 2: - sam.USB_DEVICE.EPSTATUSCLR2.Set(val) - case 3: - sam.USB_DEVICE.EPSTATUSCLR3.Set(val) - case 4: - sam.USB_DEVICE.EPSTATUSCLR4.Set(val) - case 5: - sam.USB_DEVICE.EPSTATUSCLR5.Set(val) - case 6: - sam.USB_DEVICE.EPSTATUSCLR6.Set(val) - case 7: - sam.USB_DEVICE.EPSTATUSCLR7.Set(val) - default: - return - } -} - -func setEPSTATUSSET(ep uint32, val uint8) { - switch ep { - case 0: - sam.USB_DEVICE.EPSTATUSSET0.Set(val) - case 1: - sam.USB_DEVICE.EPSTATUSSET1.Set(val) - case 2: - sam.USB_DEVICE.EPSTATUSSET2.Set(val) - case 3: - sam.USB_DEVICE.EPSTATUSSET3.Set(val) - case 4: - sam.USB_DEVICE.EPSTATUSSET4.Set(val) - case 5: - sam.USB_DEVICE.EPSTATUSSET5.Set(val) - case 6: - sam.USB_DEVICE.EPSTATUSSET6.Set(val) - case 7: - sam.USB_DEVICE.EPSTATUSSET7.Set(val) - default: - return - } -} - -func getEPSTATUS(ep uint32) uint8 { - switch ep { - case 0: - return sam.USB_DEVICE.EPSTATUS0.Get() - case 1: - return sam.USB_DEVICE.EPSTATUS1.Get() - case 2: - return sam.USB_DEVICE.EPSTATUS2.Get() - case 3: - return sam.USB_DEVICE.EPSTATUS3.Get() - case 4: - return sam.USB_DEVICE.EPSTATUS4.Get() - case 5: - return sam.USB_DEVICE.EPSTATUS5.Get() - case 6: - return sam.USB_DEVICE.EPSTATUS6.Get() - case 7: - return sam.USB_DEVICE.EPSTATUS7.Get() - default: - return 0 - } -} - -func getEPINTFLAG(ep uint32) uint8 { - switch ep { - case 0: - return sam.USB_DEVICE.EPINTFLAG0.Get() - case 1: - return sam.USB_DEVICE.EPINTFLAG1.Get() - case 2: - return sam.USB_DEVICE.EPINTFLAG2.Get() - case 3: - return sam.USB_DEVICE.EPINTFLAG3.Get() - case 4: - return sam.USB_DEVICE.EPINTFLAG4.Get() - case 5: - return sam.USB_DEVICE.EPINTFLAG5.Get() - case 6: - return sam.USB_DEVICE.EPINTFLAG6.Get() - case 7: - return sam.USB_DEVICE.EPINTFLAG7.Get() - default: - return 0 - } -} - -func setEPINTFLAG(ep uint32, val uint8) { - switch ep { - case 0: - sam.USB_DEVICE.EPINTFLAG0.Set(val) - case 1: - sam.USB_DEVICE.EPINTFLAG1.Set(val) - case 2: - sam.USB_DEVICE.EPINTFLAG2.Set(val) - case 3: - sam.USB_DEVICE.EPINTFLAG3.Set(val) - case 4: - sam.USB_DEVICE.EPINTFLAG4.Set(val) - case 5: - sam.USB_DEVICE.EPINTFLAG5.Set(val) - case 6: - sam.USB_DEVICE.EPINTFLAG6.Set(val) - case 7: - sam.USB_DEVICE.EPINTFLAG7.Set(val) - default: - return - } -} - -func setEPINTENCLR(ep uint32, val uint8) { - switch ep { - case 0: - sam.USB_DEVICE.EPINTENCLR0.Set(val) - case 1: - sam.USB_DEVICE.EPINTENCLR1.Set(val) - case 2: - sam.USB_DEVICE.EPINTENCLR2.Set(val) - case 3: - sam.USB_DEVICE.EPINTENCLR3.Set(val) - case 4: - sam.USB_DEVICE.EPINTENCLR4.Set(val) - case 5: - sam.USB_DEVICE.EPINTENCLR5.Set(val) - case 6: - sam.USB_DEVICE.EPINTENCLR6.Set(val) - case 7: - sam.USB_DEVICE.EPINTENCLR7.Set(val) - default: - return - } -} - -func setEPINTENSET(ep uint32, val uint8) { - switch ep { - case 0: - sam.USB_DEVICE.EPINTENSET0.Set(val) - case 1: - sam.USB_DEVICE.EPINTENSET1.Set(val) - case 2: - sam.USB_DEVICE.EPINTENSET2.Set(val) - case 3: - sam.USB_DEVICE.EPINTENSET3.Set(val) - case 4: - sam.USB_DEVICE.EPINTENSET4.Set(val) - case 5: - sam.USB_DEVICE.EPINTENSET5.Set(val) - case 6: - sam.USB_DEVICE.EPINTENSET6.Set(val) - case 7: - sam.USB_DEVICE.EPINTENSET7.Set(val) - default: - return - } -} diff --git a/emb/machine/machine_atsamd21e18.go b/emb/machine/machine_atsamd21e18.go deleted file mode 100644 index 85d6853..0000000 --- a/emb/machine/machine_atsamd21e18.go +++ /dev/null @@ -1,359 +0,0 @@ -//go:build sam && atsamd21 && atsamd21e18 - -// Peripheral abstraction layer for the atsamd21. -// -// Datasheet: -// http://ww1.microchip.com/downloads/en/DeviceDoc/SAMD21-Family-DataSheet-DS40001882D.pdf -package machine - -import ( - "device/sam" - "runtime/interrupt" -) - -var ( - sercomUSART0 = UART{Buffer: NewRingBuffer(), Bus: sam.SERCOM0_USART, SERCOM: 0} - sercomUSART1 = UART{Buffer: NewRingBuffer(), Bus: sam.SERCOM1_USART, SERCOM: 1} - sercomUSART2 = UART{Buffer: NewRingBuffer(), Bus: sam.SERCOM2_USART, SERCOM: 2} - sercomUSART3 = UART{Buffer: NewRingBuffer(), Bus: sam.SERCOM3_USART, SERCOM: 3} - - sercomI2CM0 = &I2C{Bus: sam.SERCOM0_I2CM, SERCOM: 0} - sercomI2CM1 = &I2C{Bus: sam.SERCOM1_I2CM, SERCOM: 1} - sercomI2CM2 = &I2C{Bus: sam.SERCOM2_I2CM, SERCOM: 2} - sercomI2CM3 = &I2C{Bus: sam.SERCOM3_I2CM, SERCOM: 3} - - sercomSPIM0 = &SPI{Bus: sam.SERCOM0_SPI, SERCOM: 0} - sercomSPIM1 = &SPI{Bus: sam.SERCOM1_SPI, SERCOM: 1} - sercomSPIM2 = &SPI{Bus: sam.SERCOM2_SPI, SERCOM: 2} - sercomSPIM3 = &SPI{Bus: sam.SERCOM3_SPI, SERCOM: 3} -) - -func init() { - sercomUSART0.Interrupt = interrupt.New(sam.IRQ_SERCOM0, sercomUSART0.handleInterrupt) - sercomUSART1.Interrupt = interrupt.New(sam.IRQ_SERCOM1, sercomUSART1.handleInterrupt) - sercomUSART2.Interrupt = interrupt.New(sam.IRQ_SERCOM2, sercomUSART2.handleInterrupt) - sercomUSART3.Interrupt = interrupt.New(sam.IRQ_SERCOM3, sercomUSART3.handleInterrupt) -} - -// Return the register and mask to enable a given GPIO pin. This can be used to -// implement bit-banged drivers. -func (p Pin) PortMaskSet() (*uint32, uint32) { - return &sam.PORT.OUTSET0.Reg, 1 << uint8(p) -} - -// Return the register and mask to disable a given port. This can be used to -// implement bit-banged drivers. -func (p Pin) PortMaskClear() (*uint32, uint32) { - return &sam.PORT.OUTCLR0.Reg, 1 << uint8(p) -} - -// Set the pin to high or low. -// Warning: only use this on an output pin! -func (p Pin) Set(high bool) { - if high { - sam.PORT.OUTSET0.Set(1 << uint8(p)) - } else { - sam.PORT.OUTCLR0.Set(1 << uint8(p)) - } -} - -// Get returns the current value of a GPIO pin when configured as an input or as -// an output. -func (p Pin) Get() bool { - return (sam.PORT.IN0.Get()>>uint8(p))&1 > 0 -} - -// Configure this pin with the given configuration. -func (p Pin) Configure(config PinConfig) { - switch config.Mode { - case PinOutput: - sam.PORT.DIRSET0.Set(1 << uint8(p)) - // output is also set to input enable so pin can read back its own value - p.setPinCfg(sam.PORT_PINCFG0_INEN) - - case PinInput: - sam.PORT.DIRCLR0.Set(1 << uint8(p)) - p.setPinCfg(sam.PORT_PINCFG0_INEN) - - case PinInputPulldown: - sam.PORT.DIRCLR0.Set(1 << uint8(p)) - sam.PORT.OUTCLR0.Set(1 << uint8(p)) - p.setPinCfg(sam.PORT_PINCFG0_INEN | sam.PORT_PINCFG0_PULLEN) - - case PinInputPullup: - sam.PORT.DIRCLR0.Set(1 << uint8(p)) - sam.PORT.OUTSET0.Set(1 << uint8(p)) - p.setPinCfg(sam.PORT_PINCFG0_INEN | sam.PORT_PINCFG0_PULLEN) - - case PinSERCOM: - if uint8(p)&1 > 0 { - // odd pin, so save the even pins - val := p.getPMux() & sam.PORT_PMUX0_PMUXE_Msk - p.setPMux(val | (uint8(PinSERCOM) << sam.PORT_PMUX0_PMUXO_Pos)) - } else { - // even pin, so save the odd pins - val := p.getPMux() & sam.PORT_PMUX0_PMUXO_Msk - p.setPMux(val | (uint8(PinSERCOM) << sam.PORT_PMUX0_PMUXE_Pos)) - } - // enable port config - p.setPinCfg(sam.PORT_PINCFG0_PMUXEN | sam.PORT_PINCFG0_DRVSTR | sam.PORT_PINCFG0_INEN) - - case PinSERCOMAlt: - if uint8(p)&1 > 0 { - // odd pin, so save the even pins - val := p.getPMux() & sam.PORT_PMUX0_PMUXE_Msk - p.setPMux(val | (uint8(PinSERCOMAlt) << sam.PORT_PMUX0_PMUXO_Pos)) - } else { - // even pin, so save the odd pins - val := p.getPMux() & sam.PORT_PMUX0_PMUXO_Msk - p.setPMux(val | (uint8(PinSERCOMAlt) << sam.PORT_PMUX0_PMUXE_Pos)) - } - // enable port config - p.setPinCfg(sam.PORT_PINCFG0_PMUXEN | sam.PORT_PINCFG0_DRVSTR) - - case PinCom: - if uint8(p)&1 > 0 { - // odd pin, so save the even pins - val := p.getPMux() & sam.PORT_PMUX0_PMUXE_Msk - p.setPMux(val | (uint8(PinCom) << sam.PORT_PMUX0_PMUXO_Pos)) - } else { - // even pin, so save the odd pins - val := p.getPMux() & sam.PORT_PMUX0_PMUXO_Msk - p.setPMux(val | (uint8(PinCom) << sam.PORT_PMUX0_PMUXE_Pos)) - } - // enable port config - p.setPinCfg(sam.PORT_PINCFG0_PMUXEN) - case PinAnalog: - if uint8(p)&1 > 0 { - // odd pin, so save the even pins - val := p.getPMux() & sam.PORT_PMUX0_PMUXE_Msk - p.setPMux(val | (uint8(PinAnalog) << sam.PORT_PMUX0_PMUXO_Pos)) - } else { - // even pin, so save the odd pins - val := p.getPMux() & sam.PORT_PMUX0_PMUXO_Msk - p.setPMux(val | (uint8(PinAnalog) << sam.PORT_PMUX0_PMUXE_Pos)) - } - // enable port config - p.setPinCfg(sam.PORT_PINCFG0_PMUXEN | sam.PORT_PINCFG0_DRVSTR) - } -} - -// getPMux returns the value for the correct PMUX register for this pin. -func (p Pin) getPMux() uint8 { - switch p >> 1 { - case 0: - return sam.PORT.PMUX0_0.Get() - case 1: - return sam.PORT.PMUX0_1.Get() - case 2: - return sam.PORT.PMUX0_2.Get() - case 3: - return sam.PORT.PMUX0_3.Get() - case 4: - return sam.PORT.PMUX0_4.Get() - case 5: - return sam.PORT.PMUX0_5.Get() - case 6: - return sam.PORT.PMUX0_6.Get() - case 7: - return sam.PORT.PMUX0_7.Get() - case 8: - return sam.PORT.PMUX0_8.Get() - case 9: - return sam.PORT.PMUX0_9.Get() - case 10: - return sam.PORT.PMUX0_10.Get() - case 11: - return sam.PORT.PMUX0_11.Get() - case 12: - return sam.PORT.PMUX0_12.Get() - case 13: - return sam.PORT.PMUX0_13.Get() - case 14: - return sam.PORT.PMUX0_14.Get() - case 15: - return sam.PORT.PMUX0_15.Get() - default: - return 0 - } -} - -// setPMux sets the value for the correct PMUX register for this pin. -func (p Pin) setPMux(val uint8) { - switch p >> 1 { - case 0: - sam.PORT.PMUX0_0.Set(val) - case 1: - sam.PORT.PMUX0_1.Set(val) - case 2: - sam.PORT.PMUX0_2.Set(val) - case 3: - sam.PORT.PMUX0_3.Set(val) - case 4: - sam.PORT.PMUX0_4.Set(val) - case 5: - sam.PORT.PMUX0_5.Set(val) - case 6: - sam.PORT.PMUX0_6.Set(val) - case 7: - sam.PORT.PMUX0_7.Set(val) - case 8: - sam.PORT.PMUX0_8.Set(val) - case 9: - sam.PORT.PMUX0_9.Set(val) - case 10: - sam.PORT.PMUX0_10.Set(val) - case 11: - sam.PORT.PMUX0_11.Set(val) - case 12: - sam.PORT.PMUX0_12.Set(val) - case 13: - sam.PORT.PMUX0_13.Set(val) - case 14: - sam.PORT.PMUX0_14.Set(val) - case 15: - sam.PORT.PMUX0_15.Set(val) - } -} - -// getPinCfg returns the value for the correct PINCFG register for this pin. -func (p Pin) getPinCfg() uint8 { - switch p { - case 0: - return sam.PORT.PINCFG0_0.Get() - case 1: - return sam.PORT.PINCFG0_1.Get() - case 2: - return sam.PORT.PINCFG0_2.Get() - case 3: - return sam.PORT.PINCFG0_3.Get() - case 4: - return sam.PORT.PINCFG0_4.Get() - case 5: - return sam.PORT.PINCFG0_5.Get() - case 6: - return sam.PORT.PINCFG0_6.Get() - case 7: - return sam.PORT.PINCFG0_7.Get() - case 8: - return sam.PORT.PINCFG0_8.Get() - case 9: - return sam.PORT.PINCFG0_9.Get() - case 10: - return sam.PORT.PINCFG0_10.Get() - case 11: - return sam.PORT.PINCFG0_11.Get() - case 12: - return sam.PORT.PINCFG0_12.Get() - case 13: - return sam.PORT.PINCFG0_13.Get() - case 14: - return sam.PORT.PINCFG0_14.Get() - case 15: - return sam.PORT.PINCFG0_15.Get() - case 16: - return sam.PORT.PINCFG0_16.Get() - case 17: - return sam.PORT.PINCFG0_17.Get() - case 18: - return sam.PORT.PINCFG0_18.Get() - case 19: - return sam.PORT.PINCFG0_19.Get() - case 20: - return sam.PORT.PINCFG0_20.Get() - case 21: - return sam.PORT.PINCFG0_21.Get() - case 22: - return sam.PORT.PINCFG0_22.Get() - case 23: - return sam.PORT.PINCFG0_23.Get() - case 24: - return sam.PORT.PINCFG0_24.Get() - case 25: - return sam.PORT.PINCFG0_25.Get() - case 26: - return sam.PORT.PINCFG0_26.Get() - case 27: - return sam.PORT.PINCFG0_27.Get() - case 28: - return sam.PORT.PINCFG0_28.Get() - case 29: - return sam.PORT.PINCFG0_29.Get() - case 30: - return sam.PORT.PINCFG0_30.Get() - case 31: - return sam.PORT.PINCFG0_31.Get() - default: - return 0 - } -} - -// setPinCfg sets the value for the correct PINCFG register for this pin. -func (p Pin) setPinCfg(val uint8) { - switch p { - case 0: - sam.PORT.PINCFG0_0.Set(val) - case 1: - sam.PORT.PINCFG0_1.Set(val) - case 2: - sam.PORT.PINCFG0_2.Set(val) - case 3: - sam.PORT.PINCFG0_3.Set(val) - case 4: - sam.PORT.PINCFG0_4.Set(val) - case 5: - sam.PORT.PINCFG0_5.Set(val) - case 6: - sam.PORT.PINCFG0_6.Set(val) - case 7: - sam.PORT.PINCFG0_7.Set(val) - case 8: - sam.PORT.PINCFG0_8.Set(val) - case 9: - sam.PORT.PINCFG0_9.Set(val) - case 10: - sam.PORT.PINCFG0_10.Set(val) - case 11: - sam.PORT.PINCFG0_11.Set(val) - case 12: - sam.PORT.PINCFG0_12.Set(val) - case 13: - sam.PORT.PINCFG0_13.Set(val) - case 14: - sam.PORT.PINCFG0_14.Set(val) - case 15: - sam.PORT.PINCFG0_15.Set(val) - case 16: - sam.PORT.PINCFG0_16.Set(val) - case 17: - sam.PORT.PINCFG0_17.Set(val) - case 18: - sam.PORT.PINCFG0_18.Set(val) - case 19: - sam.PORT.PINCFG0_19.Set(val) - case 20: - sam.PORT.PINCFG0_20.Set(val) - case 21: - sam.PORT.PINCFG0_21.Set(val) - case 22: - sam.PORT.PINCFG0_22.Set(val) - case 23: - sam.PORT.PINCFG0_23.Set(val) - case 24: - sam.PORT.PINCFG0_24.Set(val) - case 25: - sam.PORT.PINCFG0_25.Set(val) - case 26: - sam.PORT.PINCFG0_26.Set(val) - case 27: - sam.PORT.PINCFG0_27.Set(val) - case 28: - sam.PORT.PINCFG0_28.Set(val) - case 29: - sam.PORT.PINCFG0_29.Set(val) - case 30: - sam.PORT.PINCFG0_30.Set(val) - case 31: - sam.PORT.PINCFG0_31.Set(val) - } -} diff --git a/emb/machine/machine_atsamd21g18.go b/emb/machine/machine_atsamd21g18.go deleted file mode 100644 index 9e845cf..0000000 --- a/emb/machine/machine_atsamd21g18.go +++ /dev/null @@ -1,606 +0,0 @@ -//go:build sam && atsamd21 && atsamd21g18 - -// Peripheral abstraction layer for the atsamd21. -// -// Datasheet: -// http://ww1.microchip.com/downloads/en/DeviceDoc/SAMD21-Family-DataSheet-DS40001882D.pdf -package machine - -import ( - "device/sam" - "runtime/interrupt" -) - -var ( - sercomUSART0 = UART{Buffer: NewRingBuffer(), Bus: sam.SERCOM0_USART, SERCOM: 0} - sercomUSART1 = UART{Buffer: NewRingBuffer(), Bus: sam.SERCOM1_USART, SERCOM: 1} - sercomUSART2 = UART{Buffer: NewRingBuffer(), Bus: sam.SERCOM2_USART, SERCOM: 2} - sercomUSART3 = UART{Buffer: NewRingBuffer(), Bus: sam.SERCOM3_USART, SERCOM: 3} - sercomUSART4 = UART{Buffer: NewRingBuffer(), Bus: sam.SERCOM4_USART, SERCOM: 4} - sercomUSART5 = UART{Buffer: NewRingBuffer(), Bus: sam.SERCOM5_USART, SERCOM: 5} - - sercomI2CM0 = &I2C{Bus: sam.SERCOM0_I2CM, SERCOM: 0} - sercomI2CM1 = &I2C{Bus: sam.SERCOM1_I2CM, SERCOM: 1} - sercomI2CM2 = &I2C{Bus: sam.SERCOM2_I2CM, SERCOM: 2} - sercomI2CM3 = &I2C{Bus: sam.SERCOM3_I2CM, SERCOM: 3} - sercomI2CM4 = &I2C{Bus: sam.SERCOM4_I2CM, SERCOM: 4} - sercomI2CM5 = &I2C{Bus: sam.SERCOM5_I2CM, SERCOM: 5} - - sercomSPIM0 = &SPI{Bus: sam.SERCOM0_SPI, SERCOM: 0} - sercomSPIM1 = &SPI{Bus: sam.SERCOM1_SPI, SERCOM: 1} - sercomSPIM2 = &SPI{Bus: sam.SERCOM2_SPI, SERCOM: 2} - sercomSPIM3 = &SPI{Bus: sam.SERCOM3_SPI, SERCOM: 3} - sercomSPIM4 = &SPI{Bus: sam.SERCOM4_SPI, SERCOM: 4} - sercomSPIM5 = &SPI{Bus: sam.SERCOM5_SPI, SERCOM: 5} -) - -func init() { - sercomUSART0.Interrupt = interrupt.New(sam.IRQ_SERCOM0, sercomUSART0.handleInterrupt) - sercomUSART1.Interrupt = interrupt.New(sam.IRQ_SERCOM1, sercomUSART1.handleInterrupt) - sercomUSART2.Interrupt = interrupt.New(sam.IRQ_SERCOM2, sercomUSART2.handleInterrupt) - sercomUSART3.Interrupt = interrupt.New(sam.IRQ_SERCOM3, sercomUSART3.handleInterrupt) - sercomUSART4.Interrupt = interrupt.New(sam.IRQ_SERCOM4, sercomUSART4.handleInterrupt) - sercomUSART5.Interrupt = interrupt.New(sam.IRQ_SERCOM5, sercomUSART5.handleInterrupt) -} - -// Return the register and mask to enable a given GPIO pin. This can be used to -// implement bit-banged drivers. -func (p Pin) PortMaskSet() (*uint32, uint32) { - // Note: using PORT_IOBUS for faster pin accesses. - // The regular PORT registers appear to take around 4 clock cycles to store, - // which is longer than the ws2812 driver expects. The IOBUS is is fast - // enough to avoid this issue. - if p < 32 { - return &sam.PORT_IOBUS.OUTSET0.Reg, 1 << uint8(p) - } else { - return &sam.PORT_IOBUS.OUTSET1.Reg, 1 << uint8(p-32) - } -} - -// Return the register and mask to disable a given port. This can be used to -// implement bit-banged drivers. -func (p Pin) PortMaskClear() (*uint32, uint32) { - if p < 32 { - return &sam.PORT_IOBUS.OUTCLR0.Reg, 1 << uint8(p) - } else { - return &sam.PORT_IOBUS.OUTCLR1.Reg, 1 << uint8(p-32) - } -} - -// Set the pin to high or low. -// Warning: only use this on an output pin! -func (p Pin) Set(high bool) { - if p < 32 { - if high { - sam.PORT.OUTSET0.Set(1 << uint8(p)) - } else { - sam.PORT.OUTCLR0.Set(1 << uint8(p)) - } - } else { - if high { - sam.PORT.OUTSET1.Set(1 << uint8(p-32)) - } else { - sam.PORT.OUTCLR1.Set(1 << uint8(p-32)) - } - } -} - -// Get returns the current value of a GPIO pin when configured as an input or as -// an output. -func (p Pin) Get() bool { - if p < 32 { - return (sam.PORT.IN0.Get()>>uint8(p))&1 > 0 - } else { - return (sam.PORT.IN1.Get()>>uint8(p-32))&1 > 0 - } -} - -// Configure this pin with the given configuration. -func (p Pin) Configure(config PinConfig) { - switch config.Mode { - case PinOutput: - if p < 32 { - sam.PORT.DIRSET0.Set(1 << uint8(p)) - // output is also set to input enable so pin can read back its own value - p.setPinCfg(sam.PORT_PINCFG0_INEN) - } else { - sam.PORT.DIRSET1.Set(1 << uint8(p-32)) - // output is also set to input enable so pin can read back its own value - p.setPinCfg(sam.PORT_PINCFG0_INEN) - } - - case PinInput: - if p < 32 { - sam.PORT.DIRCLR0.Set(1 << uint8(p)) - p.setPinCfg(sam.PORT_PINCFG0_INEN) - } else { - sam.PORT.DIRCLR1.Set(1 << uint8(p-32)) - p.setPinCfg(sam.PORT_PINCFG0_INEN) - } - - case PinInputPulldown: - if p < 32 { - sam.PORT.DIRCLR0.Set(1 << uint8(p)) - sam.PORT.OUTCLR0.Set(1 << uint8(p)) - p.setPinCfg(sam.PORT_PINCFG0_INEN | sam.PORT_PINCFG0_PULLEN) - } else { - sam.PORT.DIRCLR1.Set(1 << uint8(p-32)) - sam.PORT.OUTCLR1.Set(1 << uint8(p-32)) - p.setPinCfg(sam.PORT_PINCFG0_INEN | sam.PORT_PINCFG0_PULLEN) - } - - case PinInputPullup: - if p < 32 { - sam.PORT.DIRCLR0.Set(1 << uint8(p)) - sam.PORT.OUTSET0.Set(1 << uint8(p)) - p.setPinCfg(sam.PORT_PINCFG0_INEN | sam.PORT_PINCFG0_PULLEN) - } else { - sam.PORT.DIRCLR1.Set(1 << uint8(p-32)) - sam.PORT.OUTSET1.Set(1 << uint8(p-32)) - p.setPinCfg(sam.PORT_PINCFG0_INEN | sam.PORT_PINCFG0_PULLEN) - } - - case PinSERCOM: - if p&1 > 0 { - // odd pin, so save the even pins - val := p.getPMux() & sam.PORT_PMUX0_PMUXE_Msk - p.setPMux(val | (uint8(PinSERCOM) << sam.PORT_PMUX0_PMUXO_Pos)) - } else { - // even pin, so save the odd pins - val := p.getPMux() & sam.PORT_PMUX0_PMUXO_Msk - p.setPMux(val | (uint8(PinSERCOM) << sam.PORT_PMUX0_PMUXE_Pos)) - } - // enable port config - p.setPinCfg(sam.PORT_PINCFG0_PMUXEN | sam.PORT_PINCFG0_DRVSTR | sam.PORT_PINCFG0_INEN) - - case PinSERCOMAlt: - if p&1 > 0 { - // odd pin, so save the even pins - val := p.getPMux() & sam.PORT_PMUX0_PMUXE_Msk - p.setPMux(val | (uint8(PinSERCOMAlt) << sam.PORT_PMUX0_PMUXO_Pos)) - } else { - // even pin, so save the odd pins - val := p.getPMux() & sam.PORT_PMUX0_PMUXO_Msk - p.setPMux(val | (uint8(PinSERCOMAlt) << sam.PORT_PMUX0_PMUXE_Pos)) - } - // enable port config - p.setPinCfg(sam.PORT_PINCFG0_PMUXEN | sam.PORT_PINCFG0_DRVSTR) - - case PinCom: - if p&1 > 0 { - // odd pin, so save the even pins - val := p.getPMux() & sam.PORT_PMUX0_PMUXE_Msk - p.setPMux(val | (uint8(PinCom) << sam.PORT_PMUX0_PMUXO_Pos)) - } else { - // even pin, so save the odd pins - val := p.getPMux() & sam.PORT_PMUX0_PMUXO_Msk - p.setPMux(val | (uint8(PinCom) << sam.PORT_PMUX0_PMUXE_Pos)) - } - // enable port config - p.setPinCfg(sam.PORT_PINCFG0_PMUXEN) - case PinAnalog: - if p&1 > 0 { - // odd pin, so save the even pins - val := p.getPMux() & sam.PORT_PMUX0_PMUXE_Msk - p.setPMux(val | (uint8(PinAnalog) << sam.PORT_PMUX0_PMUXO_Pos)) - } else { - // even pin, so save the odd pins - val := p.getPMux() & sam.PORT_PMUX0_PMUXO_Msk - p.setPMux(val | (uint8(PinAnalog) << sam.PORT_PMUX0_PMUXE_Pos)) - } - // enable port config - p.setPinCfg(sam.PORT_PINCFG0_PMUXEN | sam.PORT_PINCFG0_DRVSTR) - } -} - -// getPMux returns the value for the correct PMUX register for this pin. -func (p Pin) getPMux() uint8 { - switch uint8(p) >> 1 { - case 0: - return sam.PORT.PMUX0_0.Get() - case 1: - return sam.PORT.PMUX0_1.Get() - case 2: - return sam.PORT.PMUX0_2.Get() - case 3: - return sam.PORT.PMUX0_3.Get() - case 4: - return sam.PORT.PMUX0_4.Get() - case 5: - return sam.PORT.PMUX0_5.Get() - case 6: - return sam.PORT.PMUX0_6.Get() - case 7: - return sam.PORT.PMUX0_7.Get() - case 8: - return sam.PORT.PMUX0_8.Get() - case 9: - return sam.PORT.PMUX0_9.Get() - case 10: - return sam.PORT.PMUX0_10.Get() - case 11: - return sam.PORT.PMUX0_11.Get() - case 12: - return sam.PORT.PMUX0_12.Get() - case 13: - return sam.PORT.PMUX0_13.Get() - case 14: - return sam.PORT.PMUX0_14.Get() - case 15: - return sam.PORT.PMUX0_15.Get() - case 16: - return uint8(sam.PORT.PMUX1_0.Get()>>0) & 0xff - case 17: - return uint8(sam.PORT.PMUX1_0.Get()>>8) & 0xff - case 18: - return uint8(sam.PORT.PMUX1_0.Get()>>16) & 0xff - case 19: - return uint8(sam.PORT.PMUX1_0.Get()>>24) & 0xff - case 20: - return uint8(sam.PORT.PMUX1_4.Get()>>0) & 0xff - case 21: - return uint8(sam.PORT.PMUX1_4.Get()>>8) & 0xff - case 22: - return uint8(sam.PORT.PMUX1_4.Get()>>16) & 0xff - case 23: - return uint8(sam.PORT.PMUX1_4.Get()>>24) & 0xff - case 24: - return uint8(sam.PORT.PMUX1_8.Get()>>0) & 0xff - case 25: - return uint8(sam.PORT.PMUX1_8.Get()>>8) & 0xff - case 26: - return uint8(sam.PORT.PMUX1_8.Get()>>16) & 0xff - case 27: - return uint8(sam.PORT.PMUX1_8.Get()>>24) & 0xff - case 28: - return uint8(sam.PORT.PMUX1_12.Get()>>0) & 0xff - case 29: - return uint8(sam.PORT.PMUX1_12.Get()>>8) & 0xff - case 30: - return uint8(sam.PORT.PMUX1_12.Get()>>16) & 0xff - case 31: - return uint8(sam.PORT.PMUX1_12.Get()>>24) & 0xff - default: - return 0 - } -} - -// setPMux sets the value for the correct PMUX register for this pin. -func (p Pin) setPMux(val uint8) { - switch uint8(p) >> 1 { - case 0: - sam.PORT.PMUX0_0.Set(val) - case 1: - sam.PORT.PMUX0_1.Set(val) - case 2: - sam.PORT.PMUX0_2.Set(val) - case 3: - sam.PORT.PMUX0_3.Set(val) - case 4: - sam.PORT.PMUX0_4.Set(val) - case 5: - sam.PORT.PMUX0_5.Set(val) - case 6: - sam.PORT.PMUX0_6.Set(val) - case 7: - sam.PORT.PMUX0_7.Set(val) - case 8: - sam.PORT.PMUX0_8.Set(val) - case 9: - sam.PORT.PMUX0_9.Set(val) - case 10: - sam.PORT.PMUX0_10.Set(val) - case 11: - sam.PORT.PMUX0_11.Set(val) - case 12: - sam.PORT.PMUX0_12.Set(val) - case 13: - sam.PORT.PMUX0_13.Set(val) - case 14: - sam.PORT.PMUX0_14.Set(val) - case 15: - sam.PORT.PMUX0_15.Set(val) - case 16: - sam.PORT.PMUX1_0.ReplaceBits(uint32(val), 0xff, 0) - case 17: - sam.PORT.PMUX1_0.ReplaceBits(uint32(val), 0xff, 8) - case 18: - sam.PORT.PMUX1_0.ReplaceBits(uint32(val), 0xff, 16) - case 19: - sam.PORT.PMUX1_0.ReplaceBits(uint32(val), 0xff, 24) - case 20: - sam.PORT.PMUX1_4.ReplaceBits(uint32(val), 0xff, 0) - case 21: - sam.PORT.PMUX1_4.ReplaceBits(uint32(val), 0xff, 8) - case 22: - sam.PORT.PMUX1_4.ReplaceBits(uint32(val), 0xff, 16) - case 23: - sam.PORT.PMUX1_4.ReplaceBits(uint32(val), 0xff, 24) - case 24: - sam.PORT.PMUX1_8.ReplaceBits(uint32(val), 0xff, 0) - case 25: - sam.PORT.PMUX1_8.ReplaceBits(uint32(val), 0xff, 8) - case 26: - sam.PORT.PMUX1_8.ReplaceBits(uint32(val), 0xff, 16) - case 27: - sam.PORT.PMUX1_8.ReplaceBits(uint32(val), 0xff, 24) - case 28: - sam.PORT.PMUX1_12.ReplaceBits(uint32(val), 0xff, 0) - case 29: - sam.PORT.PMUX1_12.ReplaceBits(uint32(val), 0xff, 8) - case 30: - sam.PORT.PMUX1_12.ReplaceBits(uint32(val), 0xff, 16) - case 31: - sam.PORT.PMUX1_12.ReplaceBits(uint32(val), 0xff, 24) - } -} - -// getPinCfg returns the value for the correct PINCFG register for this pin. -func (p Pin) getPinCfg() uint8 { - switch p { - case 0: - return sam.PORT.PINCFG0_0.Get() - case 1: - return sam.PORT.PINCFG0_1.Get() - case 2: - return sam.PORT.PINCFG0_2.Get() - case 3: - return sam.PORT.PINCFG0_3.Get() - case 4: - return sam.PORT.PINCFG0_4.Get() - case 5: - return sam.PORT.PINCFG0_5.Get() - case 6: - return sam.PORT.PINCFG0_6.Get() - case 7: - return sam.PORT.PINCFG0_7.Get() - case 8: - return sam.PORT.PINCFG0_8.Get() - case 9: - return sam.PORT.PINCFG0_9.Get() - case 10: - return sam.PORT.PINCFG0_10.Get() - case 11: - return sam.PORT.PINCFG0_11.Get() - case 12: - return sam.PORT.PINCFG0_12.Get() - case 13: - return sam.PORT.PINCFG0_13.Get() - case 14: - return sam.PORT.PINCFG0_14.Get() - case 15: - return sam.PORT.PINCFG0_15.Get() - case 16: - return sam.PORT.PINCFG0_16.Get() - case 17: - return sam.PORT.PINCFG0_17.Get() - case 18: - return sam.PORT.PINCFG0_18.Get() - case 19: - return sam.PORT.PINCFG0_19.Get() - case 20: - return sam.PORT.PINCFG0_20.Get() - case 21: - return sam.PORT.PINCFG0_21.Get() - case 22: - return sam.PORT.PINCFG0_22.Get() - case 23: - return sam.PORT.PINCFG0_23.Get() - case 24: - return sam.PORT.PINCFG0_24.Get() - case 25: - return sam.PORT.PINCFG0_25.Get() - case 26: - return sam.PORT.PINCFG0_26.Get() - case 27: - return sam.PORT.PINCFG0_27.Get() - case 28: - return sam.PORT.PINCFG0_28.Get() - case 29: - return sam.PORT.PINCFG0_29.Get() - case 30: - return sam.PORT.PINCFG0_30.Get() - case 31: - return sam.PORT.PINCFG0_31.Get() - case 32: // PB00 - return uint8(sam.PORT.PINCFG1_0.Get()>>0) & 0xff - case 33: // PB01 - return uint8(sam.PORT.PINCFG1_0.Get()>>8) & 0xff - case 34: // PB02 - return uint8(sam.PORT.PINCFG1_0.Get()>>16) & 0xff - case 35: // PB03 - return uint8(sam.PORT.PINCFG1_0.Get()>>24) & 0xff - case 36: // PB04 - return uint8(sam.PORT.PINCFG1_4.Get()>>0) & 0xff - case 37: // PB05 - return uint8(sam.PORT.PINCFG1_4.Get()>>8) & 0xff - case 38: // PB06 - return uint8(sam.PORT.PINCFG1_4.Get()>>16) & 0xff - case 39: // PB07 - return uint8(sam.PORT.PINCFG1_4.Get()>>24) & 0xff - case 40: // PB08 - return uint8(sam.PORT.PINCFG1_8.Get()>>0) & 0xff - case 41: // PB09 - return uint8(sam.PORT.PINCFG1_8.Get()>>8) & 0xff - case 42: // PB10 - return uint8(sam.PORT.PINCFG1_8.Get()>>16) & 0xff - case 43: // PB11 - return uint8(sam.PORT.PINCFG1_8.Get()>>24) & 0xff - case 44: // PB12 - return uint8(sam.PORT.PINCFG1_12.Get()>>0) & 0xff - case 45: // PB13 - return uint8(sam.PORT.PINCFG1_12.Get()>>8) & 0xff - case 46: // PB14 - return uint8(sam.PORT.PINCFG1_12.Get()>>16) & 0xff - case 47: // PB15 - return uint8(sam.PORT.PINCFG1_12.Get()>>24) & 0xff - case 48: // PB16 - return uint8(sam.PORT.PINCFG1_16.Get()>>0) & 0xff - case 49: // PB17 - return uint8(sam.PORT.PINCFG1_16.Get()>>8) & 0xff - case 50: // PB18 - return uint8(sam.PORT.PINCFG1_16.Get()>>16) & 0xff - case 51: // PB19 - return uint8(sam.PORT.PINCFG1_16.Get()>>24) & 0xff - case 52: // PB20 - return uint8(sam.PORT.PINCFG1_20.Get()>>0) & 0xff - case 53: // PB21 - return uint8(sam.PORT.PINCFG1_20.Get()>>8) & 0xff - case 54: // PB22 - return uint8(sam.PORT.PINCFG1_20.Get()>>16) & 0xff - case 55: // PB23 - return uint8(sam.PORT.PINCFG1_20.Get()>>24) & 0xff - case 56: // PB24 - return uint8(sam.PORT.PINCFG1_24.Get()>>0) & 0xff - case 57: // PB25 - return uint8(sam.PORT.PINCFG1_24.Get()>>8) & 0xff - case 58: // PB26 - return uint8(sam.PORT.PINCFG1_24.Get()>>16) & 0xff - case 59: // PB27 - return uint8(sam.PORT.PINCFG1_24.Get()>>24) & 0xff - case 60: // PB28 - return uint8(sam.PORT.PINCFG1_28.Get()>>0) & 0xff - case 61: // PB29 - return uint8(sam.PORT.PINCFG1_28.Get()>>8) & 0xff - case 62: // PB30 - return uint8(sam.PORT.PINCFG1_28.Get()>>16) & 0xff - case 63: // PB31 - return uint8(sam.PORT.PINCFG1_28.Get()>>24) & 0xff - default: - return 0 - } -} - -// setPinCfg sets the value for the correct PINCFG register for this pin. -func (p Pin) setPinCfg(val uint8) { - switch p { - case 0: - sam.PORT.PINCFG0_0.Set(val) - case 1: - sam.PORT.PINCFG0_1.Set(val) - case 2: - sam.PORT.PINCFG0_2.Set(val) - case 3: - sam.PORT.PINCFG0_3.Set(val) - case 4: - sam.PORT.PINCFG0_4.Set(val) - case 5: - sam.PORT.PINCFG0_5.Set(val) - case 6: - sam.PORT.PINCFG0_6.Set(val) - case 7: - sam.PORT.PINCFG0_7.Set(val) - case 8: - sam.PORT.PINCFG0_8.Set(val) - case 9: - sam.PORT.PINCFG0_9.Set(val) - case 10: - sam.PORT.PINCFG0_10.Set(val) - case 11: - sam.PORT.PINCFG0_11.Set(val) - case 12: - sam.PORT.PINCFG0_12.Set(val) - case 13: - sam.PORT.PINCFG0_13.Set(val) - case 14: - sam.PORT.PINCFG0_14.Set(val) - case 15: - sam.PORT.PINCFG0_15.Set(val) - case 16: - sam.PORT.PINCFG0_16.Set(val) - case 17: - sam.PORT.PINCFG0_17.Set(val) - case 18: - sam.PORT.PINCFG0_18.Set(val) - case 19: - sam.PORT.PINCFG0_19.Set(val) - case 20: - sam.PORT.PINCFG0_20.Set(val) - case 21: - sam.PORT.PINCFG0_21.Set(val) - case 22: - sam.PORT.PINCFG0_22.Set(val) - case 23: - sam.PORT.PINCFG0_23.Set(val) - case 24: - sam.PORT.PINCFG0_24.Set(val) - case 25: - sam.PORT.PINCFG0_25.Set(val) - case 26: - sam.PORT.PINCFG0_26.Set(val) - case 27: - sam.PORT.PINCFG0_27.Set(val) - case 28: - sam.PORT.PINCFG0_28.Set(val) - case 29: - sam.PORT.PINCFG0_29.Set(val) - case 30: - sam.PORT.PINCFG0_30.Set(val) - case 31: - sam.PORT.PINCFG0_31.Set(val) - case 32: // PB00 - sam.PORT.PINCFG1_0.ReplaceBits(uint32(val), 0xff, 0) - case 33: // PB01 - sam.PORT.PINCFG1_0.ReplaceBits(uint32(val), 0xff, 8) - case 34: // PB02 - sam.PORT.PINCFG1_0.ReplaceBits(uint32(val), 0xff, 16) - case 35: // PB03 - sam.PORT.PINCFG1_0.ReplaceBits(uint32(val), 0xff, 24) - case 36: // PB04 - sam.PORT.PINCFG1_4.ReplaceBits(uint32(val), 0xff, 0) - case 37: // PB05 - sam.PORT.PINCFG1_4.ReplaceBits(uint32(val), 0xff, 8) - case 38: // PB06 - sam.PORT.PINCFG1_4.ReplaceBits(uint32(val), 0xff, 16) - case 39: // PB07 - sam.PORT.PINCFG1_4.ReplaceBits(uint32(val), 0xff, 24) - case 40: // PB08 - sam.PORT.PINCFG1_8.ReplaceBits(uint32(val), 0xff, 0) - case 41: // PB09 - sam.PORT.PINCFG1_8.ReplaceBits(uint32(val), 0xff, 8) - case 42: // PB10 - sam.PORT.PINCFG1_8.ReplaceBits(uint32(val), 0xff, 16) - case 43: // PB11 - sam.PORT.PINCFG1_8.ReplaceBits(uint32(val), 0xff, 24) - case 44: // PB12 - sam.PORT.PINCFG1_12.ReplaceBits(uint32(val), 0xff, 0) - case 45: // PB13 - sam.PORT.PINCFG1_12.ReplaceBits(uint32(val), 0xff, 8) - case 46: // PB14 - sam.PORT.PINCFG1_12.ReplaceBits(uint32(val), 0xff, 16) - case 47: // PB15 - sam.PORT.PINCFG1_12.ReplaceBits(uint32(val), 0xff, 24) - case 48: // PB16 - sam.PORT.PINCFG1_16.ReplaceBits(uint32(val), 0xff, 0) - case 49: // PB17 - sam.PORT.PINCFG1_16.ReplaceBits(uint32(val), 0xff, 8) - case 50: // PB18 - sam.PORT.PINCFG1_16.ReplaceBits(uint32(val), 0xff, 16) - case 51: // PB19 - sam.PORT.PINCFG1_16.ReplaceBits(uint32(val), 0xff, 24) - case 52: // PB20 - sam.PORT.PINCFG1_20.ReplaceBits(uint32(val), 0xff, 0) - case 53: // PB21 - sam.PORT.PINCFG1_20.ReplaceBits(uint32(val), 0xff, 8) - case 54: // PB22 - sam.PORT.PINCFG1_20.ReplaceBits(uint32(val), 0xff, 16) - case 55: // PB23 - sam.PORT.PINCFG1_20.ReplaceBits(uint32(val), 0xff, 24) - case 56: // PB24 - sam.PORT.PINCFG1_24.ReplaceBits(uint32(val), 0xff, 0) - case 57: // PB25 - sam.PORT.PINCFG1_24.ReplaceBits(uint32(val), 0xff, 8) - case 58: // PB26 - sam.PORT.PINCFG1_24.ReplaceBits(uint32(val), 0xff, 16) - case 59: // PB27 - sam.PORT.PINCFG1_24.ReplaceBits(uint32(val), 0xff, 24) - case 60: // PB28 - sam.PORT.PINCFG1_28.ReplaceBits(uint32(val), 0xff, 0) - case 61: // PB29 - sam.PORT.PINCFG1_28.ReplaceBits(uint32(val), 0xff, 8) - case 62: // PB30 - sam.PORT.PINCFG1_28.ReplaceBits(uint32(val), 0xff, 16) - case 63: // PB31 - sam.PORT.PINCFG1_28.ReplaceBits(uint32(val), 0xff, 24) - } -} diff --git a/emb/machine/machine_atsamd51.go b/emb/machine/machine_atsamd51.go deleted file mode 100644 index 576f454..0000000 --- a/emb/machine/machine_atsamd51.go +++ /dev/null @@ -1,2358 +0,0 @@ -//go:build (sam && atsamd51) || (sam && atsame5x) - -// Peripheral abstraction layer for the atsamd51. -// -// Datasheet: -// http://ww1.microchip.com/downloads/en/DeviceDoc/60001507C.pdf -package machine - -import ( - "device/arm" - "device/sam" - "errors" - "internal/binary" - "runtime/interrupt" - "unsafe" -) - -const deviceName = sam.Device - -// DS60001507, Section 9.6: Serial Number -var deviceIDAddr = []uintptr{0x008061FC, 0x00806010, 0x00806014, 0x00806018} - -func CPUFrequency() uint32 { - return 120000000 -} - -const ( - PinAnalog PinMode = 1 - PinSERCOM PinMode = 2 - PinSERCOMAlt PinMode = 3 - PinTimer PinMode = 4 - PinTimerAlt PinMode = 5 - PinTCCPDEC PinMode = 6 - PinCom PinMode = 7 - PinSDHC PinMode = 8 - PinI2S PinMode = 9 - PinPCC PinMode = 10 - PinGMAC PinMode = 11 - PinACCLK PinMode = 12 - PinCCL PinMode = 13 - PinDigital PinMode = 14 - PinInput PinMode = 15 - PinInputPullup PinMode = 16 - PinOutput PinMode = 17 - PinTCCE PinMode = PinTimer - PinTCCF PinMode = PinTimerAlt - PinTCCG PinMode = PinTCCPDEC - PinInputPulldown PinMode = 18 - PinCAN PinMode = 19 - PinCAN0 PinMode = PinSDHC - PinCAN1 PinMode = PinCom -) - -type PinChange uint8 - -// Pin change interrupt constants for SetInterrupt. -const ( - PinRising PinChange = sam.EIC_CONFIG_SENSE0_RISE - PinFalling PinChange = sam.EIC_CONFIG_SENSE0_FALL - PinToggle PinChange = sam.EIC_CONFIG_SENSE0_BOTH -) - -// Callbacks to be called for pins configured with SetInterrupt. Unfortunately, -// we also need to keep track of which interrupt channel is used by which pin, -// as the only alternative would be iterating through all pins. -// -// We're using the magic constant 16 here because the SAM D21 has 16 interrupt -// channels configurable for pins. -var ( - interruptPins [16]Pin // warning: the value is invalid when pinCallbacks[i] is not set! - pinCallbacks [16]func(Pin) -) - -// Hardware pins -const ( - PA00 Pin = 0 - PA01 Pin = 1 - PA02 Pin = 2 - PA03 Pin = 3 - PA04 Pin = 4 - PA05 Pin = 5 - PA06 Pin = 6 - PA07 Pin = 7 - PA08 Pin = 8 // peripherals: TCC0 channel 0, TCC1 channel 4 - PA09 Pin = 9 // peripherals: TCC0 channel 1, TCC1 channel 5 - PA10 Pin = 10 // peripherals: TCC0 channel 2, TCC1 channel 6 - PA11 Pin = 11 // peripherals: TCC0 channel 3, TCC1 channel 7 - PA12 Pin = 12 // peripherals: TCC0 channel 6, TCC1 channel 2 - PA13 Pin = 13 // peripherals: TCC0 channel 7, TCC1 channel 3 - PA14 Pin = 14 // peripherals: TCC2 channel 0, TCC1 channel 2 - PA15 Pin = 15 // peripherals: TCC2 channel 1, TCC1 channel 3 - PA16 Pin = 16 // peripherals: TCC1 channel 0, TCC0 channel 4 - PA17 Pin = 17 // peripherals: TCC1 channel 1, TCC0 channel 5 - PA18 Pin = 18 // peripherals: TCC1 channel 2, TCC0 channel 6 - PA19 Pin = 19 // peripherals: TCC1 channel 3, TCC0 channel 7 - PA20 Pin = 20 // peripherals: TCC1 channel 4, TCC0 channel 0 - PA21 Pin = 21 // peripherals: TCC1 channel 5, TCC0 channel 1 - PA22 Pin = 22 // peripherals: TCC1 channel 6, TCC0 channel 2 - PA23 Pin = 23 // peripherals: TCC1 channel 7, TCC0 channel 3 - PA24 Pin = 24 // peripherals: TCC2 channel 2 - PA25 Pin = 25 // peripherals: TCC2 channel 3 - PA26 Pin = 26 - PA27 Pin = 27 - PA28 Pin = 28 - PA29 Pin = 29 - PA30 Pin = 30 // peripherals: TCC2 channel 0 - PA31 Pin = 31 // peripherals: TCC2 channel 1 - PB00 Pin = 32 - PB01 Pin = 33 - PB02 Pin = 34 // peripherals: TCC2 channel 2 - PB03 Pin = 35 // peripherals: TCC2 channel 3 - PB04 Pin = 36 - PB05 Pin = 37 - PB06 Pin = 38 - PB07 Pin = 39 - PB08 Pin = 40 - PB09 Pin = 41 - PB10 Pin = 42 // peripherals: TCC0 channel 4, TCC1 channel 0 - PB11 Pin = 43 // peripherals: TCC0 channel 5, TCC1 channel 1 - PB12 Pin = 44 // peripherals: TCC3 channel 0, TCC0 channel 0 - PB13 Pin = 45 // peripherals: TCC3 channel 1, TCC0 channel 1 - PB14 Pin = 46 // peripherals: TCC4 channel 0, TCC0 channel 2 - PB15 Pin = 47 // peripherals: TCC4 channel 1, TCC0 channel 3 - PB16 Pin = 48 // peripherals: TCC3 channel 0, TCC0 channel 4 - PB17 Pin = 49 // peripherals: TCC3 channel 1, TCC0 channel 5 - PB18 Pin = 50 // peripherals: TCC1 channel 0 - PB19 Pin = 51 // peripherals: TCC1 channel 1 - PB20 Pin = 52 // peripherals: TCC1 channel 2 - PB21 Pin = 53 // peripherals: TCC1 channel 3 - PB22 Pin = 54 - PB23 Pin = 55 - PB24 Pin = 56 - PB25 Pin = 57 - PB26 Pin = 58 // peripherals: TCC1 channel 2 - PB27 Pin = 59 // peripherals: TCC1 channel 3 - PB28 Pin = 60 // peripherals: TCC1 channel 4 - PB29 Pin = 61 // peripherals: TCC1 channel 5 - PB30 Pin = 62 // peripherals: TCC4 channel 0, TCC0 channel 6 - PB31 Pin = 63 // peripherals: TCC4 channel 1, TCC0 channel 7 - PC00 Pin = 64 - PC01 Pin = 65 - PC02 Pin = 66 - PC03 Pin = 67 - PC04 Pin = 68 // peripherals: TCC0 channel 0 - PC05 Pin = 69 // peripherals: TCC0 channel 1 - PC06 Pin = 70 - PC07 Pin = 71 - PC08 Pin = 72 - PC09 Pin = 73 - PC10 Pin = 74 // peripherals: TCC0 channel 0, TCC1 channel 4 - PC11 Pin = 75 // peripherals: TCC0 channel 1, TCC1 channel 5 - PC12 Pin = 76 // peripherals: TCC0 channel 2, TCC1 channel 6 - PC13 Pin = 77 // peripherals: TCC0 channel 3, TCC1 channel 7 - PC14 Pin = 78 // peripherals: TCC0 channel 4, TCC1 channel 0 - PC15 Pin = 79 // peripherals: TCC0 channel 5, TCC1 channel 1 - PC16 Pin = 80 // peripherals: TCC0 channel 0 - PC17 Pin = 81 // peripherals: TCC0 channel 1 - PC18 Pin = 82 // peripherals: TCC0 channel 2 - PC19 Pin = 83 // peripherals: TCC0 channel 3 - PC20 Pin = 84 // peripherals: TCC0 channel 4 - PC21 Pin = 85 // peripherals: TCC0 channel 5 - PC22 Pin = 86 // peripherals: TCC0 channel 6 - PC23 Pin = 87 // peripherals: TCC0 channel 7 - PC24 Pin = 88 - PC25 Pin = 89 - PC26 Pin = 90 - PC27 Pin = 91 - PC28 Pin = 92 - PC29 Pin = 93 - PC30 Pin = 94 - PC31 Pin = 95 - PD00 Pin = 96 - PD01 Pin = 97 - PD02 Pin = 98 - PD03 Pin = 99 - PD04 Pin = 100 - PD05 Pin = 101 - PD06 Pin = 102 - PD07 Pin = 103 - PD08 Pin = 104 // peripherals: TCC0 channel 1 - PD09 Pin = 105 // peripherals: TCC0 channel 2 - PD10 Pin = 106 // peripherals: TCC0 channel 3 - PD11 Pin = 107 // peripherals: TCC0 channel 4 - PD12 Pin = 108 // peripherals: TCC0 channel 5 - PD13 Pin = 109 // peripherals: TCC0 channel 6 - PD14 Pin = 110 - PD15 Pin = 111 - PD16 Pin = 112 - PD17 Pin = 113 - PD18 Pin = 114 - PD19 Pin = 115 - PD20 Pin = 116 // peripherals: TCC1 channel 0 - PD21 Pin = 117 // peripherals: TCC1 channel 1 - PD22 Pin = 118 - PD23 Pin = 119 - PD24 Pin = 120 - PD25 Pin = 121 - PD26 Pin = 122 - PD27 Pin = 123 - PD28 Pin = 124 - PD29 Pin = 125 - PD30 Pin = 126 - PD31 Pin = 127 -) - -const ( - pinPadMapSERCOM0Pad0 uint16 = 0x1000 - pinPadMapSERCOM1Pad0 uint16 = 0x2000 - pinPadMapSERCOM2Pad0 uint16 = 0x3000 - pinPadMapSERCOM3Pad0 uint16 = 0x4000 - pinPadMapSERCOM4Pad0 uint16 = 0x5000 - pinPadMapSERCOM5Pad0 uint16 = 0x6000 - pinPadMapSERCOM6Pad0 uint16 = 0x7000 - pinPadMapSERCOM7Pad0 uint16 = 0x8000 - pinPadMapSERCOM0Pad2 uint16 = 0x1200 - pinPadMapSERCOM1Pad2 uint16 = 0x2200 - pinPadMapSERCOM2Pad2 uint16 = 0x3200 - pinPadMapSERCOM3Pad2 uint16 = 0x4200 - pinPadMapSERCOM4Pad2 uint16 = 0x5200 - pinPadMapSERCOM5Pad2 uint16 = 0x6200 - pinPadMapSERCOM6Pad2 uint16 = 0x7200 - pinPadMapSERCOM7Pad2 uint16 = 0x8200 - - pinPadMapSERCOM0AltPad0 uint16 = 0x0010 - pinPadMapSERCOM1AltPad0 uint16 = 0x0020 - pinPadMapSERCOM2AltPad0 uint16 = 0x0030 - pinPadMapSERCOM3AltPad0 uint16 = 0x0040 - pinPadMapSERCOM4AltPad0 uint16 = 0x0050 - pinPadMapSERCOM5AltPad0 uint16 = 0x0060 - pinPadMapSERCOM6AltPad0 uint16 = 0x0070 - pinPadMapSERCOM7AltPad0 uint16 = 0x0080 - pinPadMapSERCOM0AltPad1 uint16 = 0x0011 - pinPadMapSERCOM1AltPad1 uint16 = 0x0021 - pinPadMapSERCOM2AltPad1 uint16 = 0x0031 - pinPadMapSERCOM3AltPad1 uint16 = 0x0041 - pinPadMapSERCOM4AltPad1 uint16 = 0x0051 - pinPadMapSERCOM5AltPad1 uint16 = 0x0061 - pinPadMapSERCOM6AltPad1 uint16 = 0x0071 - pinPadMapSERCOM7AltPad1 uint16 = 0x0081 - pinPadMapSERCOM0AltPad2 uint16 = 0x0012 - pinPadMapSERCOM1AltPad2 uint16 = 0x0022 - pinPadMapSERCOM2AltPad2 uint16 = 0x0032 - pinPadMapSERCOM3AltPad2 uint16 = 0x0042 - pinPadMapSERCOM4AltPad2 uint16 = 0x0052 - pinPadMapSERCOM5AltPad2 uint16 = 0x0062 - pinPadMapSERCOM6AltPad2 uint16 = 0x0072 - pinPadMapSERCOM7AltPad2 uint16 = 0x0082 -) - -// pinPadMapping lists which pins have which SERCOMs attached to them. -// The encoding is rather dense, with each uint16 encoding two pins and both -// SERCOM and SERCOM-ALT. -// -// Observations: -// - There are eight SERCOMs. Those SERCOM numbers can be encoded in 4 bits. -// - Even pad numbers are usually on even pins, and odd pad numbers are usually -// on odd pins. The exception is SERCOM-ALT, which sometimes swaps pad 0 and 1. -// With that, there is still an invariant that the pad number for an odd pin is -// the pad number for the corresponding even pin with the low bit toggled. -// - Pin pads come in pairs. If PA00 has pad 0, then PA01 has pad 1. -// -// With this information, we can encode SERCOM pin/pad numbers much more -// efficiently. Due to pads coming in pairs, we can ignore half the pins: the -// information for an odd pin can be calculated easily from the preceding even -// pin. -// -// Each word below is split in two bytes. The 8 high bytes are for SERCOM and -// the 8 low bits are for SERCOM-ALT. Of each byte, the 4 high bits encode the -// SERCOM + 1 while the two low bits encodes the pad number (the pad number for -// the odd pin can be trivially calculated by toggling the low bit of the pad -// number). It encodes SERCOM + 1 instead of just the SERCOM number, to make it -// easy to check whether a nibble is set at all. -// -// Datasheet: http://ww1.microchip.com/downloads/en/DeviceDoc/60001507E.pdf -var pinPadMapping = [64]uint16{ - // page 32 - PA00 / 2: 0 | pinPadMapSERCOM1AltPad0, - - // page 33 - PB08 / 2: 0 | pinPadMapSERCOM4AltPad0, - PA04 / 2: 0 | pinPadMapSERCOM0AltPad0, - PA06 / 2: 0 | pinPadMapSERCOM0AltPad2, - PC04 / 2: pinPadMapSERCOM6Pad0 | 0, - PC06 / 2: pinPadMapSERCOM6Pad2 | 0, - PA08 / 2: pinPadMapSERCOM0Pad0 | pinPadMapSERCOM2AltPad1, - PA10 / 2: pinPadMapSERCOM0Pad2 | pinPadMapSERCOM2AltPad2, - PB10 / 2: 0 | pinPadMapSERCOM4AltPad2, - PB12 / 2: pinPadMapSERCOM4Pad0 | 0, - PB14 / 2: pinPadMapSERCOM4Pad2 | 0, - PD08 / 2: pinPadMapSERCOM7Pad0 | pinPadMapSERCOM6AltPad1, - PD10 / 2: pinPadMapSERCOM7Pad2 | pinPadMapSERCOM6AltPad2, - PC10 / 2: pinPadMapSERCOM6Pad2 | pinPadMapSERCOM7AltPad2, - - // page 34 - PC12 / 2: pinPadMapSERCOM7Pad0 | pinPadMapSERCOM6AltPad1, - PC14 / 2: pinPadMapSERCOM7Pad2 | pinPadMapSERCOM6AltPad2, - PA12 / 2: pinPadMapSERCOM2Pad0 | pinPadMapSERCOM4AltPad1, - PA14 / 2: pinPadMapSERCOM2Pad2 | pinPadMapSERCOM4AltPad2, - PA16 / 2: pinPadMapSERCOM1Pad0 | pinPadMapSERCOM3AltPad1, - PA18 / 2: pinPadMapSERCOM1Pad2 | pinPadMapSERCOM3AltPad2, - PC16 / 2: pinPadMapSERCOM6Pad0 | pinPadMapSERCOM0AltPad1, - PC18 / 2: pinPadMapSERCOM6Pad2 | pinPadMapSERCOM0AltPad2, - PC22 / 2: pinPadMapSERCOM1Pad0 | pinPadMapSERCOM3AltPad1, - PD20 / 2: pinPadMapSERCOM1Pad2 | pinPadMapSERCOM3AltPad2, - PB16 / 2: pinPadMapSERCOM5Pad0 | 0, - PB18 / 2: pinPadMapSERCOM5Pad2 | pinPadMapSERCOM7AltPad2, - - // page 35 - PB20 / 2: pinPadMapSERCOM3Pad0 | pinPadMapSERCOM7AltPad1, - PA20 / 2: pinPadMapSERCOM5Pad2 | pinPadMapSERCOM3AltPad2, - PA22 / 2: pinPadMapSERCOM3Pad0 | pinPadMapSERCOM5AltPad1, - PA24 / 2: pinPadMapSERCOM3Pad2 | pinPadMapSERCOM5AltPad2, - PB22 / 2: pinPadMapSERCOM1Pad2 | pinPadMapSERCOM5AltPad2, - PB24 / 2: pinPadMapSERCOM0Pad0 | pinPadMapSERCOM2AltPad1, - PB26 / 2: pinPadMapSERCOM2Pad0 | pinPadMapSERCOM4AltPad1, - PB28 / 2: pinPadMapSERCOM2Pad2 | pinPadMapSERCOM4AltPad2, - PC24 / 2: pinPadMapSERCOM0Pad2 | pinPadMapSERCOM2AltPad2, - //PC26 / 2: pinPadMapSERCOM1Pad1 | 0, // note: PC26 doesn't support SERCOM, but PC27 does - //PC28 / 2: pinPadMapSERCOM1Pad1 | 0, // note: PC29 doesn't exist in the datasheet? - PA30 / 2: 0 | pinPadMapSERCOM1AltPad2, - - // page 36 - PB30 / 2: 0 | pinPadMapSERCOM5AltPad1, - PB00 / 2: 0 | pinPadMapSERCOM5AltPad2, - PB02 / 2: 0 | pinPadMapSERCOM5AltPad0, -} - -// findPinPadMapping looks up the pad number and the pinmode for a given pin and -// SERCOM number. The result can either be SERCOM, SERCOM-ALT, or "not found" -// (indicated by returning ok=false). The pad number is returned to calculate -// the DOPO/DIPO bitfields of the various serial peripherals. -func findPinPadMapping(sercom uint8, pin Pin) (pinMode PinMode, pad uint32, ok bool) { - if int(pin)/2 >= len(pinPadMapping) { - // This is probably NoPin, for which no mapping is available. - return - } - - bytes := pinPadMapping[pin/2] - upper := byte(bytes >> 8) - lower := byte(bytes & 0xff) - - if upper != 0 { - // SERCOM - if (upper>>4)-1 == sercom { - pinMode = PinSERCOM - pad |= uint32(upper % 4) - ok = true - } - } - if lower != 0 { - // SERCOM-ALT - if (lower>>4)-1 == sercom { - pinMode = PinSERCOMAlt - pad |= uint32(lower % 4) - ok = true - } - } - - if ok { - // If the pin is uneven, toggle the lowest bit of the pad number. - if pin&1 != 0 { - pad ^= 1 - } - } - return -} - -// SetInterrupt sets an interrupt to be executed when a particular pin changes -// state. The pin should already be configured as an input, including a pull up -// or down if no external pull is provided. -// -// This call will replace a previously set callback on this pin. You can pass a -// nil func to unset the pin change interrupt. If you do so, the change -// parameter is ignored and can be set to any value (such as 0). -func (p Pin) SetInterrupt(change PinChange, callback func(Pin)) error { - // Most pins follow a common pattern where the EXTINT value is the pin - // number modulo 16. However, there are a few exceptions, as you can see - // below. - extint := uint8(0) - - switch p { - case PA08: - // Connected to NMI. This is not currently supported. - return ErrInvalidInputPin - case PB26: - extint = 12 - case PB27: - extint = 13 - case PB28: - extint = 14 - case PB29: - extint = 15 - case PC07: - extint = 9 - case PD08: - extint = 3 - case PD09: - extint = 4 - case PD10: - extint = 5 - case PD11: - extint = 6 - case PD12: - extint = 7 - case PD20: - extint = 10 - case PD21: - extint = 11 - default: - // All other pins follow a normal pattern. - extint = uint8(p) % 16 - } - - if callback == nil { - // Disable this pin interrupt (if it was enabled). - sam.EIC.INTENCLR.Set(1 << extint) - if pinCallbacks[extint] != nil { - pinCallbacks[extint] = nil - } - return nil - } - - if pinCallbacks[extint] != nil { - // The pin was already configured. - // To properly re-configure a pin, unset it first and set a new - // configuration. - return ErrNoPinChangeChannel - } - pinCallbacks[extint] = callback - interruptPins[extint] = p - - if !sam.EIC.CTRLA.HasBits(sam.EIC_CTRLA_ENABLE) { - // EIC peripheral has not yet been initialized. Initialize it now. - - // The EIC needs two clocks: CLK_EIC_APB and GCLK_EIC. CLK_EIC_APB is - // enabled by default, so doesn't have to be re-enabled. The other is - // required for detecting edges and must be enabled manually. - sam.GCLK.PCHCTRL[4].Set((sam.GCLK_PCHCTRL_GEN_GCLK0 << sam.GCLK_PCHCTRL_GEN_Pos) | sam.GCLK_PCHCTRL_CHEN) - - // should not be necessary (CLKCTRL is not synchronized) - for sam.GCLK.SYNCBUSY.HasBits(sam.GCLK_SYNCBUSY_GENCTRL_GCLK0 << sam.GCLK_SYNCBUSY_GENCTRL_Pos) { - } - } - - // CONFIG register is enable-protected, so disable EIC. - sam.EIC.CTRLA.ClearBits(sam.EIC_CTRLA_ENABLE) - - // Configure this pin. Set the 4 bits of the EIC.CONFIGx register to the - // sense value (filter bit set to 0, sense bits set to the change value). - addr := &sam.EIC.CONFIG[0] - if extint >= 8 { - addr = &sam.EIC.CONFIG[1] - } - pos := (extint % 8) * 4 // bit position in register - addr.ReplaceBits(uint32(change), 0xf, pos) - - // Enable external interrupt for this pin. - sam.EIC.INTENSET.Set(1 << extint) - - sam.EIC.CTRLA.Set(sam.EIC_CTRLA_ENABLE) - for sam.EIC.SYNCBUSY.HasBits(sam.EIC_SYNCBUSY_ENABLE) { - } - - // Set the PMUXEN flag, while keeping the INEN and PULLEN flags (if they - // were set before). This avoids clearing the pin pull mode while - // configuring the pin interrupt. - p.setPinCfg(sam.PORT_GROUP_PINCFG_PMUXEN | (p.getPinCfg() & (sam.PORT_GROUP_PINCFG_INEN | sam.PORT_GROUP_PINCFG_PULLEN))) - if p&1 > 0 { - // odd pin, so save the even pins - val := p.getPMux() & sam.PORT_GROUP_PMUX_PMUXE_Msk - p.setPMux(val | (0 << sam.PORT_GROUP_PMUX_PMUXO_Pos)) - } else { - // even pin, so save the odd pins - val := p.getPMux() & sam.PORT_GROUP_PMUX_PMUXO_Msk - p.setPMux(val | (0 << sam.PORT_GROUP_PMUX_PMUXE_Pos)) - } - - handleEICInterrupt := func(interrupt.Interrupt) { - flags := sam.EIC.INTFLAG.Get() - sam.EIC.INTFLAG.Set(flags) // clear interrupt - for i := uint(0); i < 16; i++ { // there are 16 channels - if flags&(1<>pin_in_group)&1 > 0 -} - -// Toggle switches an output pin from low to high or from high to low. -// Warning: only use this on an output pin! -func (p Pin) Toggle() { - group, pin_in_group := p.getPinGrouping() - sam.PORT.GROUP[group].OUTTGL.Set(1 << pin_in_group) -} - -// Configure this pin with the given configuration. -func (p Pin) Configure(config PinConfig) { - group, pin_in_group := p.getPinGrouping() - switch config.Mode { - case PinOutput: - sam.PORT.GROUP[group].DIRSET.Set(1 << pin_in_group) - // output is also set to input enable so pin can read back its own value - p.setPinCfg(sam.PORT_GROUP_PINCFG_INEN) - - case PinInput: - sam.PORT.GROUP[group].DIRCLR.Set(1 << pin_in_group) - p.setPinCfg(sam.PORT_GROUP_PINCFG_INEN) - - case PinInputPulldown: - sam.PORT.GROUP[group].DIRCLR.Set(1 << pin_in_group) - sam.PORT.GROUP[group].OUTCLR.Set(1 << pin_in_group) - p.setPinCfg(sam.PORT_GROUP_PINCFG_INEN | sam.PORT_GROUP_PINCFG_PULLEN) - - case PinInputPullup: - sam.PORT.GROUP[group].DIRCLR.Set(1 << pin_in_group) - sam.PORT.GROUP[group].OUTSET.Set(1 << pin_in_group) - p.setPinCfg(sam.PORT_GROUP_PINCFG_INEN | sam.PORT_GROUP_PINCFG_PULLEN) - - case PinSERCOM: - if p&1 > 0 { - // odd pin, so save the even pins - val := p.getPMux() & sam.PORT_GROUP_PMUX_PMUXE_Msk - p.setPMux(val | (uint8(PinSERCOM) << sam.PORT_GROUP_PMUX_PMUXO_Pos)) - } else { - // even pin, so save the odd pins - val := p.getPMux() & sam.PORT_GROUP_PMUX_PMUXO_Msk - p.setPMux(val | (uint8(PinSERCOM) << sam.PORT_GROUP_PMUX_PMUXE_Pos)) - } - // enable port config - p.setPinCfg(sam.PORT_GROUP_PINCFG_PMUXEN | sam.PORT_GROUP_PINCFG_DRVSTR | sam.PORT_GROUP_PINCFG_INEN) - - case PinSERCOMAlt: - if p&1 > 0 { - // odd pin, so save the even pins - val := p.getPMux() & sam.PORT_GROUP_PMUX_PMUXE_Msk - p.setPMux(val | (uint8(PinSERCOMAlt) << sam.PORT_GROUP_PMUX_PMUXO_Pos)) - } else { - // even pin, so save the odd pins - val := p.getPMux() & sam.PORT_GROUP_PMUX_PMUXO_Msk - p.setPMux(val | (uint8(PinSERCOMAlt) << sam.PORT_GROUP_PMUX_PMUXE_Pos)) - } - // enable port config - p.setPinCfg(sam.PORT_GROUP_PINCFG_PMUXEN | sam.PORT_GROUP_PINCFG_DRVSTR) - - case PinCom: - if p&1 > 0 { - // odd pin, so save the even pins - val := p.getPMux() & sam.PORT_GROUP_PMUX_PMUXE_Msk - p.setPMux(val | (uint8(PinCom) << sam.PORT_GROUP_PMUX_PMUXO_Pos)) - } else { - // even pin, so save the odd pins - val := p.getPMux() & sam.PORT_GROUP_PMUX_PMUXO_Msk - p.setPMux(val | (uint8(PinCom) << sam.PORT_GROUP_PMUX_PMUXE_Pos)) - } - // enable port config - p.setPinCfg(sam.PORT_GROUP_PINCFG_PMUXEN) - case PinAnalog: - if p&1 > 0 { - // odd pin, so save the even pins - val := p.getPMux() & sam.PORT_GROUP_PMUX_PMUXE_Msk - p.setPMux(val | (uint8(PinAnalog) << sam.PORT_GROUP_PMUX_PMUXO_Pos)) - } else { - // even pin, so save the odd pins - val := p.getPMux() & sam.PORT_GROUP_PMUX_PMUXO_Msk - p.setPMux(val | (uint8(PinAnalog) << sam.PORT_GROUP_PMUX_PMUXE_Pos)) - } - // enable port config - p.setPinCfg(sam.PORT_GROUP_PINCFG_PMUXEN | sam.PORT_GROUP_PINCFG_DRVSTR) - case PinSDHC: - if p&1 > 0 { - // odd pin, so save the even pins - val := p.getPMux() & sam.PORT_GROUP_PMUX_PMUXE_Msk - p.setPMux(val | (uint8(PinSDHC) << sam.PORT_GROUP_PMUX_PMUXO_Pos)) - } else { - // even pin, so save the odd pins - val := p.getPMux() & sam.PORT_GROUP_PMUX_PMUXO_Msk - p.setPMux(val | (uint8(PinSDHC) << sam.PORT_GROUP_PMUX_PMUXE_Pos)) - } - // enable port config - p.setPinCfg(sam.PORT_GROUP_PINCFG_PMUXEN) - } -} - -// getPMux returns the value for the correct PMUX register for this pin. -func (p Pin) getPMux() uint8 { - group, pin_in_group := p.getPinGrouping() - return sam.PORT.GROUP[group].PMUX[pin_in_group>>1].Get() -} - -// setPMux sets the value for the correct PMUX register for this pin. -func (p Pin) setPMux(val uint8) { - group, pin_in_group := p.getPinGrouping() - sam.PORT.GROUP[group].PMUX[pin_in_group>>1].Set(val) -} - -// getPinCfg returns the value for the correct PINCFG register for this pin. -func (p Pin) getPinCfg() uint8 { - group, pin_in_group := p.getPinGrouping() - return sam.PORT.GROUP[group].PINCFG[pin_in_group].Get() -} - -// setPinCfg sets the value for the correct PINCFG register for this pin. -func (p Pin) setPinCfg(val uint8) { - group, pin_in_group := p.getPinGrouping() - sam.PORT.GROUP[group].PINCFG[pin_in_group].Set(val) -} - -// getPinGrouping calculates the gpio group and pin id from the pin number. -// Pins are split into groups of 32, and each group has its own set of -// control registers. -func (p Pin) getPinGrouping() (uint8, uint8) { - group := uint8(p) >> 5 - pin_in_group := uint8(p) & 0x1f - return group, pin_in_group -} - -// InitADC initializes the ADC. -func InitADC() { - // ADC Bias Calibration - // NVMCTRL_SW0 0x00800080 - // #define ADC0_FUSES_BIASCOMP_ADDR NVMCTRL_SW0 - // #define ADC0_FUSES_BIASCOMP_Pos 2 /**< \brief (NVMCTRL_SW0) ADC Comparator Scaling */ - // #define ADC0_FUSES_BIASCOMP_Msk (_Ul(0x7) << ADC0_FUSES_BIASCOMP_Pos) - // #define ADC0_FUSES_BIASCOMP(value) (ADC0_FUSES_BIASCOMP_Msk & ((value) << ADC0_FUSES_BIASCOMP_Pos)) - - // #define ADC0_FUSES_BIASR2R_ADDR NVMCTRL_SW0 - // #define ADC0_FUSES_BIASR2R_Pos 8 /**< \brief (NVMCTRL_SW0) ADC Bias R2R ampli scaling */ - // #define ADC0_FUSES_BIASR2R_Msk (_Ul(0x7) << ADC0_FUSES_BIASR2R_Pos) - // #define ADC0_FUSES_BIASR2R(value) (ADC0_FUSES_BIASR2R_Msk & ((value) << ADC0_FUSES_BIASR2R_Pos)) - - // #define ADC0_FUSES_BIASREFBUF_ADDR NVMCTRL_SW0 - // #define ADC0_FUSES_BIASREFBUF_Pos 5 /**< \brief (NVMCTRL_SW0) ADC Bias Reference Buffer Scaling */ - // #define ADC0_FUSES_BIASREFBUF_Msk (_Ul(0x7) << ADC0_FUSES_BIASREFBUF_Pos) - // #define ADC0_FUSES_BIASREFBUF(value) (ADC0_FUSES_BIASREFBUF_Msk & ((value) << ADC0_FUSES_BIASREFBUF_Pos)) - - // #define ADC1_FUSES_BIASCOMP_ADDR NVMCTRL_SW0 - // #define ADC1_FUSES_BIASCOMP_Pos 16 /**< \brief (NVMCTRL_SW0) ADC Comparator Scaling */ - // #define ADC1_FUSES_BIASCOMP_Msk (_Ul(0x7) << ADC1_FUSES_BIASCOMP_Pos) - // #define ADC1_FUSES_BIASCOMP(value) (ADC1_FUSES_BIASCOMP_Msk & ((value) << ADC1_FUSES_BIASCOMP_Pos)) - - // #define ADC1_FUSES_BIASR2R_ADDR NVMCTRL_SW0 - // #define ADC1_FUSES_BIASR2R_Pos 22 /**< \brief (NVMCTRL_SW0) ADC Bias R2R ampli scaling */ - // #define ADC1_FUSES_BIASR2R_Msk (_Ul(0x7) << ADC1_FUSES_BIASR2R_Pos) - // #define ADC1_FUSES_BIASR2R(value) (ADC1_FUSES_BIASR2R_Msk & ((value) << ADC1_FUSES_BIASR2R_Pos)) - - // #define ADC1_FUSES_BIASREFBUF_ADDR NVMCTRL_SW0 - // #define ADC1_FUSES_BIASREFBUF_Pos 19 /**< \brief (NVMCTRL_SW0) ADC Bias Reference Buffer Scaling */ - // #define ADC1_FUSES_BIASREFBUF_Msk (_Ul(0x7) << ADC1_FUSES_BIASREFBUF_Pos) - // #define ADC1_FUSES_BIASREFBUF(value) (ADC1_FUSES_BIASREFBUF_Msk & ((value) << ADC1_FUSES_BIASREFBUF_Pos)) - - adcFuse := *(*uint32)(unsafe.Pointer(uintptr(0x00800080))) - - // uint32_t biascomp = (*((uint32_t *)ADC0_FUSES_BIASCOMP_ADDR) & ADC0_FUSES_BIASCOMP_Msk) >> ADC0_FUSES_BIASCOMP_Pos; - biascomp := (adcFuse & uint32(0x7<<2)) //>> 2 - - // uint32_t biasr2r = (*((uint32_t *)ADC0_FUSES_BIASR2R_ADDR) & ADC0_FUSES_BIASR2R_Msk) >> ADC0_FUSES_BIASR2R_Pos; - biasr2r := (adcFuse & uint32(0x7<<8)) //>> 8 - - // uint32_t biasref = (*((uint32_t *)ADC0_FUSES_BIASREFBUF_ADDR) & ADC0_FUSES_BIASREFBUF_Msk) >> ADC0_FUSES_BIASREFBUF_Pos; - biasref := (adcFuse & uint32(0x7<<5)) //>> 5 - - // calibrate ADC0 - sam.ADC0.CALIB.Set(uint16(biascomp | biasr2r | biasref)) - - // biascomp = (*((uint32_t *)ADC1_FUSES_BIASCOMP_ADDR) & ADC1_FUSES_BIASCOMP_Msk) >> ADC1_FUSES_BIASCOMP_Pos; - biascomp = (adcFuse & uint32(0x7<<16)) //>> 16 - - // biasr2r = (*((uint32_t *)ADC1_FUSES_BIASR2R_ADDR) & ADC1_FUSES_BIASR2R_Msk) >> ADC1_FUSES_BIASR2R_Pos; - biasr2r = (adcFuse & uint32(0x7<<22)) //>> 22 - - // biasref = (*((uint32_t *)ADC1_FUSES_BIASREFBUF_ADDR) & ADC1_FUSES_BIASREFBUF_Msk) >> ADC1_FUSES_BIASREFBUF_Pos; - biasref = (adcFuse & uint32(0x7<<19)) //>> 19 - - // calibrate ADC1 - sam.ADC1.CALIB.Set(uint16((biascomp | biasr2r | biasref) >> 16)) -} - -// Configure configures a ADCPin to be able to be used to read data. -func (a ADC) Configure(config ADCConfig) { - - for _, adc := range []*sam.ADC_Type{sam.ADC0, sam.ADC1} { - - for adc.SYNCBUSY.HasBits(sam.ADC_SYNCBUSY_CTRLB) { - } // wait for sync - - // Averaging (see datasheet table in AVGCTRL register description) - var resolution uint32 = sam.ADC_CTRLB_RESSEL_16BIT - var samples uint32 - switch config.Samples { - case 2: - samples = sam.ADC_AVGCTRL_SAMPLENUM_2 - case 4: - samples = sam.ADC_AVGCTRL_SAMPLENUM_4 - case 8: - samples = sam.ADC_AVGCTRL_SAMPLENUM_8 - case 16: - samples = sam.ADC_AVGCTRL_SAMPLENUM_16 - case 32: - samples = sam.ADC_AVGCTRL_SAMPLENUM_32 - case 64: - samples = sam.ADC_AVGCTRL_SAMPLENUM_64 - case 128: - samples = sam.ADC_AVGCTRL_SAMPLENUM_128 - case 256: - samples = sam.ADC_AVGCTRL_SAMPLENUM_256 - case 512: - samples = sam.ADC_AVGCTRL_SAMPLENUM_512 - case 1024: - samples = sam.ADC_AVGCTRL_SAMPLENUM_1024 - default: // 1 sample only (no oversampling nor averaging), adjusting result by 0 - // Resolutions less than 16 bits only make sense when sampling only - // once. Resulting ADC values become erratic when using both - // multi-sampling and less than 16 bits of resolution. - samples = sam.ADC_AVGCTRL_SAMPLENUM_1 - switch config.Resolution { - case 8: - resolution = sam.ADC_CTRLB_RESSEL_8BIT - case 10: - resolution = sam.ADC_CTRLB_RESSEL_10BIT - case 12: - resolution = sam.ADC_CTRLB_RESSEL_12BIT - case 16: - resolution = sam.ADC_CTRLB_RESSEL_16BIT - default: - resolution = sam.ADC_CTRLB_RESSEL_12BIT - } - } - - adc.AVGCTRL.Set(uint8(samples<> sam.ADC_CTRLB_RESSEL_Pos { - case sam.ADC_CTRLB_RESSEL_8BIT: - val = val << 8 - case sam.ADC_CTRLB_RESSEL_10BIT: - val = val << 6 - case sam.ADC_CTRLB_RESSEL_12BIT: - val = val << 4 - case sam.ADC_CTRLB_RESSEL_16BIT: - // Adjust for multiple samples. This is only configured when the - // resolution is 16 bits. - switch (bus.AVGCTRL.Get() & sam.ADC_AVGCTRL_SAMPLENUM_Msk) >> sam.ADC_AVGCTRL_SAMPLENUM_Pos { - case sam.ADC_AVGCTRL_SAMPLENUM_1: - val <<= 4 - case sam.ADC_AVGCTRL_SAMPLENUM_2: - val <<= 3 - case sam.ADC_AVGCTRL_SAMPLENUM_4: - val <<= 2 - case sam.ADC_AVGCTRL_SAMPLENUM_8: - val <<= 1 - default: - // These values are all shifted by the hardware so they fit exactly - // in a 16-bit integer, so they don't need to be shifted here. - } - } - return val -} - -func (a ADC) getADCBus() *sam.ADC_Type { - if (a.Pin >= PB04 && a.Pin <= PB07) || (a.Pin >= PC00) { - return sam.ADC1 - } - return sam.ADC0 -} - -func (a ADC) getADCChannel() uint8 { - switch a.Pin { - case PA02: - return 0 - case PB08: - return 2 - case PB09: - return 3 - case PA04: - return 4 - case PA05: - return 5 - case PA06: - return 6 - case PA07: - return 7 - case PB00: - return 12 - case PB01: - return 13 - case PB02: - return 14 - case PB03: - return 15 - case PA09: - return 17 - case PA11: - return 19 - - case PB04: - return 6 - case PB05: - return 7 - case PB06: - return 8 - case PB07: - return 9 - - case PC00: - return 10 - case PC01: - return 11 - case PC02: - return 4 - case PC03: - return 5 - case PC30: - return 12 - case PC31: - return 13 - - case PD00: - return 14 - case PD01: - return 15 - default: - panic("Invalid ADC pin") - } -} - -// UART on the SAMD51. -type UART struct { - Buffer *RingBuffer - Bus *sam.SERCOM_USART_INT_Type - SERCOM uint8 - Interrupt interrupt.Interrupt // RXC interrupt -} - -var ( - sercomUSART0 = UART{Buffer: NewRingBuffer(), Bus: sam.SERCOM0_USART_INT, SERCOM: 0} - sercomUSART1 = UART{Buffer: NewRingBuffer(), Bus: sam.SERCOM1_USART_INT, SERCOM: 1} - sercomUSART2 = UART{Buffer: NewRingBuffer(), Bus: sam.SERCOM2_USART_INT, SERCOM: 2} - sercomUSART3 = UART{Buffer: NewRingBuffer(), Bus: sam.SERCOM3_USART_INT, SERCOM: 3} - sercomUSART4 = UART{Buffer: NewRingBuffer(), Bus: sam.SERCOM4_USART_INT, SERCOM: 4} - sercomUSART5 = UART{Buffer: NewRingBuffer(), Bus: sam.SERCOM5_USART_INT, SERCOM: 5} -) - -func init() { - sercomUSART0.Interrupt = interrupt.New(sam.IRQ_SERCOM0_2, sercomUSART0.handleInterrupt) - sercomUSART1.Interrupt = interrupt.New(sam.IRQ_SERCOM1_2, sercomUSART1.handleInterrupt) - sercomUSART2.Interrupt = interrupt.New(sam.IRQ_SERCOM2_2, sercomUSART2.handleInterrupt) - sercomUSART3.Interrupt = interrupt.New(sam.IRQ_SERCOM3_2, sercomUSART3.handleInterrupt) - sercomUSART4.Interrupt = interrupt.New(sam.IRQ_SERCOM4_2, sercomUSART4.handleInterrupt) - sercomUSART5.Interrupt = interrupt.New(sam.IRQ_SERCOM5_2, sercomUSART5.handleInterrupt) -} - -const ( - sampleRate16X = 16 - lsbFirst = 1 -) - -// Configure the UART. -func (uart *UART) Configure(config UARTConfig) error { - // Default baud rate to 115200. - if config.BaudRate == 0 { - config.BaudRate = 115200 - } - - // determine pins - if config.TX == 0 && config.RX == 0 { - // use default pins - config.TX = UART_TX_PIN - config.RX = UART_RX_PIN - } - - // Determine transmit pinout. - txPinMode, txPad, ok := findPinPadMapping(uart.SERCOM, config.TX) - if !ok { - return ErrInvalidOutputPin - } - var txPadOut uint32 - // See CTRLA.RXPO bits of the SERCOM USART peripheral (page 945-946) for how - // pads are mapped to pinout values. - switch txPad { - case 0: - txPadOut = 0 - default: - // should be flow control (RTS/CTS) pin - return ErrInvalidOutputPin - } - - // Determine receive pinout. - rxPinMode, rxPad, ok := findPinPadMapping(uart.SERCOM, config.RX) - if !ok { - return ErrInvalidInputPin - } - // As you can see in the CTRLA.RXPO bits of the SERCOM USART peripheral - // (page 945), input pins are mapped directly. - rxPadOut := rxPad - - // configure pins - config.TX.Configure(PinConfig{Mode: txPinMode}) - config.RX.Configure(PinConfig{Mode: rxPinMode}) - - // configure RTS/CTS pins if provided - if config.RTS != 0 && config.CTS != 0 { - rtsPinMode, _, ok := findPinPadMapping(uart.SERCOM, config.RTS) - if !ok { - return ErrInvalidOutputPin - } - - ctsPinMode, _, ok := findPinPadMapping(uart.SERCOM, config.CTS) - if !ok { - return ErrInvalidInputPin - } - - // See CTRLA.RXPO bits of the SERCOM USART peripheral (page 945-946) for how - // pads are mapped to pinout values. - txPadOut = 2 - - config.RTS.Configure(PinConfig{Mode: rtsPinMode}) - config.CTS.Configure(PinConfig{Mode: ctsPinMode}) - } - - // reset SERCOM - uart.Bus.CTRLA.SetBits(sam.SERCOM_USART_INT_CTRLA_SWRST) - for uart.Bus.CTRLA.HasBits(sam.SERCOM_USART_INT_CTRLA_SWRST) || - uart.Bus.SYNCBUSY.HasBits(sam.SERCOM_USART_INT_SYNCBUSY_SWRST) { - } - - // set UART mode/sample rate - // SERCOM_USART_CTRLA_MODE(mode) | - // SERCOM_USART_CTRLA_SAMPR(sampleRate); - // sam.SERCOM_USART_CTRLA_MODE_USART_INT_CLK = 1? - uart.Bus.CTRLA.Set((1 << sam.SERCOM_USART_INT_CTRLA_MODE_Pos) | - (1 << sam.SERCOM_USART_INT_CTRLA_SAMPR_Pos)) // sample rate of 16x - - // set clock - setSERCOMClockGenerator(uart.SERCOM, sam.GCLK_PCHCTRL_GEN_GCLK1) - - // Set baud rate - uart.SetBaudRate(config.BaudRate) - - // setup UART frame - // SERCOM_USART_CTRLA_FORM( (parityMode == SERCOM_NO_PARITY ? 0 : 1) ) | - // dataOrder << SERCOM_USART_CTRLA_DORD_Pos; - uart.Bus.CTRLA.SetBits((0 << sam.SERCOM_USART_INT_CTRLA_FORM_Pos) | // no parity - (lsbFirst << sam.SERCOM_USART_INT_CTRLA_DORD_Pos)) // data order - - // set UART stop bits/parity - // SERCOM_USART_CTRLB_CHSIZE(charSize) | - // nbStopBits << SERCOM_USART_CTRLB_SBMODE_Pos | - // (parityMode == SERCOM_NO_PARITY ? 0 : parityMode) << SERCOM_USART_CTRLB_PMODE_Pos; //If no parity use default value - uart.Bus.CTRLB.SetBits((0 << sam.SERCOM_USART_INT_CTRLB_CHSIZE_Pos) | // 8 bits is 0 - (0 << sam.SERCOM_USART_INT_CTRLB_SBMODE_Pos) | // 1 stop bit is zero - (0 << sam.SERCOM_USART_INT_CTRLB_PMODE_Pos)) // no parity - - // set UART pads. This is not same as pins... - // SERCOM_USART_CTRLA_TXPO(txPad) | - // SERCOM_USART_CTRLA_RXPO(rxPad); - uart.Bus.CTRLA.SetBits((txPadOut << sam.SERCOM_USART_INT_CTRLA_TXPO_Pos) | - (rxPadOut << sam.SERCOM_USART_INT_CTRLA_RXPO_Pos)) - - // Enable Transceiver and Receiver - //sercom->USART.CTRLB.reg |= SERCOM_USART_CTRLB_TXEN | SERCOM_USART_CTRLB_RXEN ; - uart.Bus.CTRLB.SetBits(sam.SERCOM_USART_INT_CTRLB_TXEN | sam.SERCOM_USART_INT_CTRLB_RXEN) - - // Enable USART1 port. - // sercom->USART.CTRLA.bit.ENABLE = 0x1u; - uart.Bus.CTRLA.SetBits(sam.SERCOM_USART_INT_CTRLA_ENABLE) - for uart.Bus.SYNCBUSY.HasBits(sam.SERCOM_USART_INT_SYNCBUSY_ENABLE) { - } - - // setup interrupt on receive - uart.Bus.INTENSET.Set(sam.SERCOM_USART_INT_INTENSET_RXC) - - // Enable RX IRQ. - // This is a small note at the bottom of the NVIC section of the datasheet: - // > The integer number specified in the source refers to the respective bit - // > position in the INTFLAG register of respective peripheral. - // Therefore, if we only need to listen to the RXC interrupt source (in bit - // position 2), we only need interrupt source 2 for this SERCOM device. - uart.Interrupt.Enable() - - return nil -} - -// SetBaudRate sets the communication speed for the UART. -func (uart *UART) SetBaudRate(br uint32) { - // Asynchronous fractional mode (Table 24-2 in datasheet) - // BAUD = fref / (sampleRateValue * fbaud) - // (multiply by 8, to calculate fractional piece) - // uint32_t baudTimes8 = (SystemCoreClock * 8) / (16 * baudrate); - baud := (SERCOM_FREQ_REF * 8) / (sampleRate16X * br) - - // sercom->USART.BAUD.FRAC.FP = (baudTimes8 % 8); - // sercom->USART.BAUD.FRAC.BAUD = (baudTimes8 / 8); - uart.Bus.BAUD.Set(uint16(((baud % 8) << sam.SERCOM_USART_INT_BAUD_FRAC_MODE_FP_Pos) | - ((baud / 8) << sam.SERCOM_USART_INT_BAUD_FRAC_MODE_BAUD_Pos))) -} - -// WriteByte writes a byte of data to the UART. -func (uart *UART) writeByte(c byte) error { - // wait until ready to receive - for !uart.Bus.INTFLAG.HasBits(sam.SERCOM_USART_INT_INTFLAG_DRE) { - } - uart.Bus.DATA.Set(uint32(c)) - return nil -} - -func (uart *UART) flush() {} - -func (uart *UART) handleInterrupt(interrupt.Interrupt) { - // should reset IRQ - uart.Receive(byte((uart.Bus.DATA.Get() & 0xFF))) - uart.Bus.INTFLAG.SetBits(sam.SERCOM_USART_INT_INTFLAG_RXC) -} - -// I2C on the SAMD51. -type I2C struct { - Bus *sam.SERCOM_I2CM_Type - SERCOM uint8 -} - -// I2CConfig is used to store config info for I2C. -type I2CConfig struct { - Frequency uint32 - SCL Pin - SDA Pin -} - -const ( - // SERCOM_FREQ_REF is always reference frequency on SAMD51 regardless of CPU speed. - SERCOM_FREQ_REF = 48000000 - SERCOM_FREQ_REF_GCLK0 = 120000000 - - // Default rise time in nanoseconds, based on 4.7K ohm pull up resistors - riseTimeNanoseconds = 125 - - // wire bus states - wireUnknownState = 0 - wireIdleState = 1 - wireOwnerState = 2 - wireBusyState = 3 - - // wire commands - wireCmdNoAction = 0 - wireCmdRepeatStart = 1 - wireCmdRead = 2 - wireCmdStop = 3 -) - -const i2cTimeout = 28000 // about 210us - -// 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 - } - - // Use default I2C pins if not set. - if config.SDA == 0 && config.SCL == 0 { - config.SDA = SDA_PIN - config.SCL = SCL_PIN - } - - sclPinMode, sclPad, ok := findPinPadMapping(i2c.SERCOM, config.SCL) - if !ok || sclPad != 1 { - // SCL must be on pad 1, according to section 36.4 of the datasheet. - // Note: this is not an exhaustive test for I2C support on the pin: not - // all pins support I2C. - return ErrInvalidClockPin - } - sdaPinMode, sdaPad, ok := findPinPadMapping(i2c.SERCOM, config.SDA) - if !ok || sdaPad != 0 { - // SDA must be on pad 0, according to section 36.4 of the datasheet. - // Note: this is not an exhaustive test for I2C support on the pin: not - // all pins support I2C. - return ErrInvalidDataPin - } - - // reset SERCOM - i2c.Bus.CTRLA.SetBits(sam.SERCOM_I2CM_CTRLA_SWRST) - for i2c.Bus.CTRLA.HasBits(sam.SERCOM_I2CM_CTRLA_SWRST) || - i2c.Bus.SYNCBUSY.HasBits(sam.SERCOM_I2CM_SYNCBUSY_SWRST) { - } - - // set clock - setSERCOMClockGenerator(i2c.SERCOM, sam.GCLK_PCHCTRL_GEN_GCLK1) - - // Set i2c controller mode - //SERCOM_I2CM_CTRLA_MODE( I2C_MASTER_OPERATION ) - // sam.SERCOM_I2CM_CTRLA_MODE_I2C_MASTER = 5? - i2c.Bus.CTRLA.Set(5 << sam.SERCOM_I2CM_CTRLA_MODE_Pos) // | - - i2c.SetBaudRate(config.Frequency) - - // Enable I2CM port. - // sercom->USART.CTRLA.bit.ENABLE = 0x1u; - i2c.Bus.CTRLA.SetBits(sam.SERCOM_I2CM_CTRLA_ENABLE) - for i2c.Bus.SYNCBUSY.HasBits(sam.SERCOM_I2CM_SYNCBUSY_ENABLE) { - } - - // set bus idle mode - i2c.Bus.STATUS.SetBits(wireIdleState << sam.SERCOM_I2CM_STATUS_BUSSTATE_Pos) - for i2c.Bus.SYNCBUSY.HasBits(sam.SERCOM_I2CM_SYNCBUSY_SYSOP) { - } - - // enable pins - config.SDA.Configure(PinConfig{Mode: sdaPinMode}) - config.SCL.Configure(PinConfig{Mode: sclPinMode}) - - return nil -} - -// SetBaudRate sets the communication speed for I2C. -func (i2c *I2C) SetBaudRate(br uint32) error { - // Synchronous arithmetic baudrate, via Adafruit SAMD51 implementation: - // sercom->I2CM.BAUD.bit.BAUD = SERCOM_FREQ_REF / ( 2 * baudrate) - 1 ; - baud := SERCOM_FREQ_REF/(2*br) - 1 - i2c.Bus.BAUD.Set(baud) - 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 { - var err error - if len(w) != 0 { - // send start/address for write - i2c.sendAddress(addr, true) - - // wait until transmission complete - timeout := i2cTimeout - for !i2c.Bus.INTFLAG.HasBits(sam.SERCOM_I2CM_INTFLAG_MB) { - timeout-- - if timeout == 0 { - return errI2CWriteTimeout - } - } - - // ACK received (0: ACK, 1: NACK) - if i2c.Bus.STATUS.HasBits(sam.SERCOM_I2CM_STATUS_RXNACK) { - return errI2CAckExpected - } - - // write data - for _, b := range w { - err = i2c.WriteByte(b) - if err != nil { - return err - } - } - - err = i2c.signalStop() - if err != nil { - return err - } - } - if len(r) != 0 { - // send start/address for read - i2c.sendAddress(addr, false) - - // wait transmission complete - for !i2c.Bus.INTFLAG.HasBits(sam.SERCOM_I2CM_INTFLAG_SB) { - // If the peripheral NACKS the address, the MB bit will be set. - // In that case, send a stop condition and return error. - if i2c.Bus.INTFLAG.HasBits(sam.SERCOM_I2CM_INTFLAG_MB) { - i2c.Bus.CTRLB.SetBits(wireCmdStop << sam.SERCOM_I2CM_CTRLB_CMD_Pos) // Stop condition - return errI2CAckExpected - } - } - - // ACK received (0: ACK, 1: NACK) - if i2c.Bus.STATUS.HasBits(sam.SERCOM_I2CM_STATUS_RXNACK) { - return errI2CAckExpected - } - - // read first byte - r[0] = i2c.readByte() - for i := 1; i < len(r); i++ { - // Send an ACK - i2c.Bus.CTRLB.ClearBits(sam.SERCOM_I2CM_CTRLB_ACKACT) - - i2c.signalRead() - - // Read data and send the ACK - r[i] = i2c.readByte() - } - - // Send NACK to end transmission - i2c.Bus.CTRLB.SetBits(sam.SERCOM_I2CM_CTRLB_ACKACT) - - err = i2c.signalStop() - if err != nil { - return err - } - } - - return nil -} - -// WriteByte writes a single byte to the I2C bus. -func (i2c *I2C) WriteByte(data byte) error { - // Send data byte - i2c.Bus.DATA.Set(data) - - // wait until transmission successful - timeout := i2cTimeout - for !i2c.Bus.INTFLAG.HasBits(sam.SERCOM_I2CM_INTFLAG_MB) { - // check for bus error - if i2c.Bus.STATUS.HasBits(sam.SERCOM_I2CM_STATUS_BUSERR) { - return errI2CBusError - } - timeout-- - if timeout == 0 { - return errI2CWriteTimeout - } - } - - if i2c.Bus.STATUS.HasBits(sam.SERCOM_I2CM_STATUS_RXNACK) { - return errI2CAckExpected - } - - return nil -} - -// sendAddress sends the address and start signal -func (i2c *I2C) sendAddress(address uint16, write bool) error { - data := (address << 1) - if !write { - data |= 1 // set read flag - } - - // wait until bus ready - timeout := i2cTimeout - for !i2c.Bus.STATUS.HasBits(wireIdleState< freqGCLK1 && uint32(uint8(baudRateGCLK0-1))+1 == baudRateGCLK0 { - // Pick this 120MHz clock if it results in a better frequency after - // division, and the baudRate value fits in the BAUD register. - setSERCOMClockGenerator(spi.SERCOM, sam.GCLK_PCHCTRL_GEN_GCLK0) - spi.Bus.BAUD.Set(uint8(baudRateGCLK0 - 1)) - } else { - // Use the 48MHz clock in other cases. - setSERCOMClockGenerator(spi.SERCOM, sam.GCLK_PCHCTRL_GEN_GCLK1) - spi.Bus.BAUD.Set(uint8(baudRateGCLK1 - 1)) - } - - // Enable SPI port. - spi.Bus.CTRLA.SetBits(sam.SERCOM_SPIM_CTRLA_ENABLE) - for spi.Bus.SYNCBUSY.HasBits(sam.SERCOM_SPIM_SYNCBUSY_ENABLE) { - } - - return nil -} - -// Transfer writes/reads a single byte using the SPI interface. -func (spi *SPI) Transfer(w byte) (byte, error) { - // write data - spi.Bus.DATA.Set(uint32(w)) - - // wait for receive - for !spi.Bus.INTFLAG.HasBits(sam.SERCOM_SPIM_INTFLAG_RXC) { - } - - // return data - return byte(spi.Bus.DATA.Get()), nil -} - -// Tx handles read/write operation for SPI interface. Since SPI is a synchronous write/read -// interface, there must always be the same number of bytes written as bytes read. -// The Tx method knows about this, and offers a few different ways of calling it. -// -// This form sends the bytes in tx buffer, putting the resulting bytes read into the rx buffer. -// Note that the tx and rx buffers must be the same size: -// -// spi.Tx(tx, rx) -// -// This form sends the tx buffer, ignoring the result. Useful for sending "commands" that return zeros -// until all the bytes in the command packet have been received: -// -// spi.Tx(tx, nil) -// -// This form sends zeros, putting the result into the rx buffer. Good for reading a "result packet": -// -// spi.Tx(nil, rx) -func (spi *SPI) Tx(w, r []byte) error { - switch { - case w == nil: - // read only, so write zero and read a result. - spi.rx(r) - case r == nil: - // write only - spi.tx(w) - - default: - // write/read - if len(w) != len(r) { - return ErrTxInvalidSliceSize - } - - spi.txrx(w, r) - } - - return nil -} - -func (spi *SPI) tx(tx []byte) { - for i := 0; i < len(tx); i++ { - for !spi.Bus.INTFLAG.HasBits(sam.SERCOM_SPIM_INTFLAG_DRE) { - } - spi.Bus.DATA.Set(uint32(tx[i])) - } - for !spi.Bus.INTFLAG.HasBits(sam.SERCOM_SPIM_INTFLAG_TXC) { - } - - // read to clear RXC register - for spi.Bus.INTFLAG.HasBits(sam.SERCOM_SPIM_INTFLAG_RXC) { - spi.Bus.DATA.Get() - } -} - -func (spi *SPI) rx(rx []byte) { - spi.Bus.DATA.Set(0) - for !spi.Bus.INTFLAG.HasBits(sam.SERCOM_SPIM_INTFLAG_DRE) { - } - - for i := 1; i < len(rx); i++ { - spi.Bus.DATA.Set(0) - for !spi.Bus.INTFLAG.HasBits(sam.SERCOM_SPIM_INTFLAG_RXC) { - } - rx[i-1] = byte(spi.Bus.DATA.Get()) - } - for !spi.Bus.INTFLAG.HasBits(sam.SERCOM_SPIM_INTFLAG_RXC) { - } - rx[len(rx)-1] = byte(spi.Bus.DATA.Get()) -} - -func (spi *SPI) txrx(tx, rx []byte) { - spi.Bus.DATA.Set(uint32(tx[0])) - for !spi.Bus.INTFLAG.HasBits(sam.SERCOM_SPIM_INTFLAG_DRE) { - } - - for i := 1; i < len(rx); i++ { - spi.Bus.DATA.Set(uint32(tx[i])) - for !spi.Bus.INTFLAG.HasBits(sam.SERCOM_SPIM_INTFLAG_RXC) { - } - rx[i-1] = byte(spi.Bus.DATA.Get()) - } - for !spi.Bus.INTFLAG.HasBits(sam.SERCOM_SPIM_INTFLAG_RXC) { - } - rx[len(rx)-1] = byte(spi.Bus.DATA.Get()) -} - -// The QSPI peripheral on ATSAMD51 is only available on the following pins -const ( - QSPI_SCK = PB10 - QSPI_CS = PB11 - QSPI_DATA0 = PA08 - QSPI_DATA1 = PA09 - QSPI_DATA2 = PA10 - QSPI_DATA3 = PA11 -) - -// TCC is one timer peripheral, which consists of a counter and multiple output -// channels (that can be connected to actual pins). You can set the frequency -// using SetPeriod, but only for all the channels in this timer peripheral at -// once. -type TCC sam.TCC_Type - -//go:inline -func (tcc *TCC) timer() *sam.TCC_Type { - return (*sam.TCC_Type)(tcc) -} - -// Configure enables and configures this TCC. -func (tcc *TCC) Configure(config PWMConfig) error { - // Enable the TCC clock to be able to use the TCC. - tcc.configureClock() - - // Disable timer (if it was enabled). This is necessary because - // tcc.setPeriod may want to change the prescaler bits in CTRLA, which is - // only allowed when the TCC is disabled. - tcc.timer().CTRLA.ClearBits(sam.TCC_CTRLA_ENABLE) - - // Use "Normal PWM" (single-slope PWM) - tcc.timer().WAVE.Set(sam.TCC_WAVE_WAVEGEN_NPWM) - - // Wait for synchronization of all changed registers. - for tcc.timer().SYNCBUSY.Get() != 0 { - } - - // Set the period and prescaler. - err := tcc.setPeriod(config.Period, true) - - // Enable the timer. - tcc.timer().CTRLA.SetBits(sam.TCC_CTRLA_ENABLE) - - // Wait for synchronization of all changed registers. - for tcc.timer().SYNCBUSY.Get() != 0 { - } - - // Return any error that might have occurred in the tcc.setPeriod call. - return err -} - -// SetPeriod updates the period of this TCC peripheral. -// To set a particular frequency, use the following formula: -// -// period = 1e9 / frequency -// -// If you use a period of 0, a period that works well for LEDs will be picked. -// -// SetPeriod will not change the prescaler, but also won't change the current -// value in any of the channels. This means that you may need to update the -// value for the particular channel. -// -// Note that you cannot pick any arbitrary period after the TCC peripheral has -// been configured. If you want to switch between frequencies, pick the lowest -// frequency (longest period) once when calling Configure and adjust the -// frequency here as needed. -func (tcc *TCC) SetPeriod(period uint64) error { - return tcc.setPeriod(period, false) -} - -// setPeriod sets the period of this TCC, possibly updating the prescaler as -// well. The prescaler can only modified when the TCC is disabled, that is, in -// the Configure function. -func (tcc *TCC) setPeriod(period uint64, updatePrescaler bool) error { - var top uint64 - if period == 0 { - // Make sure the TOP value is at 0xffff (enough for a 16-bit timer). - top = 0xffff - } else { - // The formula below calculates the following formula, optimized: - // period * (120e6 / 1e9) - // This assumes that the chip is running from generic clock generator 0 - // at 120MHz. - top = period * 3 / 25 - } - - maxTop := uint64(0xffff) - if tcc.timer() == sam.TCC0 || tcc.timer() == sam.TCC1 { - // Only TCC0 and TCC1 are 24-bit timers, the rest are 16-bit. - maxTop = 0xffffff - } - - if updatePrescaler { - // This function was called during Configure(), with the timer disabled. - // Note that updating the prescaler can only happen while the peripheral - // is disabled. - var prescaler uint32 - switch { - case top <= maxTop: - prescaler = sam.TCC_CTRLA_PRESCALER_DIV1 - case top/2 <= maxTop: - prescaler = sam.TCC_CTRLA_PRESCALER_DIV2 - top = top / 2 - case top/4 <= maxTop: - prescaler = sam.TCC_CTRLA_PRESCALER_DIV4 - top = top / 4 - case top/8 <= maxTop: - prescaler = sam.TCC_CTRLA_PRESCALER_DIV8 - top = top / 8 - case top/16 <= maxTop: - prescaler = sam.TCC_CTRLA_PRESCALER_DIV16 - top = top / 16 - case top/64 <= maxTop: - prescaler = sam.TCC_CTRLA_PRESCALER_DIV64 - top = top / 64 - case top/256 <= maxTop: - prescaler = sam.TCC_CTRLA_PRESCALER_DIV256 - top = top / 256 - case top/1024 <= maxTop: - prescaler = sam.TCC_CTRLA_PRESCALER_DIV1024 - top = top / 1024 - default: - return ErrPWMPeriodTooLong - } - tcc.timer().CTRLA.Set((tcc.timer().CTRLA.Get() &^ sam.TCC_CTRLA_PRESCALER_Msk) | (prescaler << sam.TCC_CTRLA_PRESCALER_Pos)) - } else { - // Do not update the prescaler, but use the already-configured - // prescaler. This is the normal SetPeriod case, where the prescaler - // must not be changed. - prescaler := (tcc.timer().CTRLA.Get() & sam.TCC_CTRLA_PRESCALER_Msk) >> sam.TCC_CTRLA_PRESCALER_Pos - switch prescaler { - case sam.TCC_CTRLA_PRESCALER_DIV1: - top /= 1 // no-op - case sam.TCC_CTRLA_PRESCALER_DIV2: - top /= 2 - case sam.TCC_CTRLA_PRESCALER_DIV4: - top /= 4 - case sam.TCC_CTRLA_PRESCALER_DIV8: - top /= 8 - case sam.TCC_CTRLA_PRESCALER_DIV16: - top /= 16 - case sam.TCC_CTRLA_PRESCALER_DIV64: - top /= 64 - case sam.TCC_CTRLA_PRESCALER_DIV256: - top /= 256 - case sam.TCC_CTRLA_PRESCALER_DIV1024: - top /= 1024 - default: - // unreachable - } - if top > maxTop { - return ErrPWMPeriodTooLong - } - } - - // Set the period (the counter top). - tcc.timer().PER.Set(uint32(top) - 1) - - // Wait for synchronization of CTRLA.PRESCALER and PER registers. - for tcc.timer().SYNCBUSY.Get() != 0 { - } - - return nil -} - -// Top returns the current counter top, for use in duty cycle calculation. It -// will only change with a call to Configure or SetPeriod, otherwise it is -// constant. -// -// The value returned here is hardware dependent. In general, it's best to treat -// it as an opaque value that can be divided by some number and passed to -// tcc.Set (see tcc.Set for more information). -func (tcc *TCC) Top() uint32 { - return tcc.timer().PER.Get() + 1 -} - -// Counter returns the current counter value of the timer in this TCC -// peripheral. It may be useful for debugging. -func (tcc *TCC) Counter() uint32 { - tcc.timer().CTRLBSET.Set(sam.TCC_CTRLBSET_CMD_READSYNC << sam.TCC_CTRLBSET_CMD_Pos) - for tcc.timer().SYNCBUSY.Get() != 0 { - } - return tcc.timer().COUNT.Get() -} - -// Constants that encode a TCC number and WO number together in a single byte. -const ( - pinTCC0 = 1 << 4 // keep the value 0 usable as "no value" - pinTCC1 = 2 << 4 - pinTCC2 = 3 << 4 - pinTCC3 = 4 << 4 - pinTCC4 = 5 << 4 - pinTCC0_0 = pinTCC0 | 0 - pinTCC0_1 = pinTCC0 | 1 - pinTCC0_2 = pinTCC0 | 2 - pinTCC0_3 = pinTCC0 | 3 - pinTCC0_4 = pinTCC0 | 4 - pinTCC0_5 = pinTCC0 | 5 - pinTCC0_6 = pinTCC0 | 6 - pinTCC1_0 = pinTCC1 | 0 - pinTCC1_2 = pinTCC1 | 2 - pinTCC1_4 = pinTCC1 | 4 - pinTCC1_6 = pinTCC1 | 6 - pinTCC2_0 = pinTCC2 | 0 - pinTCC2_2 = pinTCC2 | 2 - pinTCC3_0 = pinTCC3 | 0 - pinTCC4_0 = pinTCC4 | 0 -) - -// This is a copy of columns F and G (the TCC columns) of table 6-1 in the -// datasheet: -// http://ww1.microchip.com/downloads/en/DeviceDoc/60001507E.pdf -// For example, "TCC0/WO[2]" is converted to pinTCC0_2. -// Only the even pin numbers are stored here. The odd pin numbers are left out, -// because their PWM output can be determined from the even number: just add one -// to the wave output (WO) number. -var pinTimerMapping = [...]struct{ F, G uint8 }{ - // page 33 - PC04 / 2: {pinTCC0_0, 0}, - PA08 / 2: {pinTCC0_0, pinTCC1_4}, - PA10 / 2: {pinTCC0_2, pinTCC1_6}, - PB10 / 2: {pinTCC0_4, pinTCC1_0}, - PB12 / 2: {pinTCC3_0, pinTCC0_0}, - PB14 / 2: {pinTCC4_0, pinTCC0_2}, - PD08 / 2: {pinTCC0_1, 0}, - PD10 / 2: {pinTCC0_3, 0}, - PD12 / 2: {pinTCC0_5, 0}, - PC10 / 2: {pinTCC0_0, pinTCC1_4}, - // page 34 - PC12 / 2: {pinTCC0_2, pinTCC1_6}, - PC14 / 2: {pinTCC0_4, pinTCC1_0}, - PA12 / 2: {pinTCC0_6, pinTCC1_2}, - PA14 / 2: {pinTCC2_0, pinTCC1_2}, - PA16 / 2: {pinTCC1_0, pinTCC0_4}, - PA18 / 2: {pinTCC1_2, pinTCC0_6}, - PC16 / 2: {pinTCC0_0, 0}, - PC18 / 2: {pinTCC0_2, 0}, - PC20 / 2: {pinTCC0_4, 0}, - PC22 / 2: {pinTCC0_6, 0}, - PD20 / 2: {pinTCC1_0, 0}, - PB16 / 2: {pinTCC3_0, pinTCC0_4}, - PB18 / 2: {pinTCC1_0, 0}, - // page 35 - PB20 / 2: {pinTCC1_2, 0}, - PA20 / 2: {pinTCC1_4, pinTCC0_0}, - PA22 / 2: {pinTCC1_6, pinTCC0_2}, - PA24 / 2: {pinTCC2_2, 0}, - PB26 / 2: {pinTCC1_2, 0}, - PB28 / 2: {pinTCC1_4, 0}, - PA30 / 2: {pinTCC2_0, 0}, - // page 36 - PB30 / 2: {pinTCC4_0, pinTCC0_6}, - PB02 / 2: {pinTCC2_2, 0}, -} - -// findPinTimerMapping returns the pin mode (PinTCCF or PinTCCG) and the channel -// number for a given timer and pin. A zero PinMode is returned if no mapping -// could be found. -func findPinTimerMapping(timer uint8, pin Pin) (PinMode, uint8) { - if int(pin/2) >= len(pinTimerMapping) { - return 0, 0 // invalid pin number - } - - mapping := pinTimerMapping[pin/2] - - // Check for column F in the datasheet. - if mapping.F>>4-1 == timer { - return PinTCCF, mapping.F&0x0f + uint8(pin)&1 - } - - // Check for column G in the datasheet. - if mapping.G>>4-1 == timer { - return PinTCCG, mapping.G&0x0f + uint8(pin)&1 - } - - // Nothing found. - return 0, 0 -} - -// Channel returns a PWM channel for the given pin. Note that one channel may be -// shared between multiple pins, and so will have the same duty cycle. If this -// is not desirable, look for a different TCC or consider using a different pin. -func (tcc *TCC) Channel(pin Pin) (uint8, error) { - pinMode, woOutput := findPinTimerMapping(tcc.timerNum(), pin) - - if pinMode == 0 { - // No pin could be found. - return 0, ErrInvalidOutputPin - } - - // Convert from waveform output to channel, assuming WEXCTRL.OTMX equals 0. - // See table 49-4 "Output Matrix Channel Pin Routing Configuration" on page - // 1829 of the datasheet. - // The number of channels varies by TCC instance, hence the need to switch - // over them. For TCC2-4 the number of channels is equal to the number of - // waveform outputs, so the WO number maps directly to the channel number. - // For TCC0 and TCC1 this is not the case so they will need some special - // handling. - channel := woOutput - switch tcc.timer() { - case sam.TCC0: - channel = woOutput % 6 - case sam.TCC1: - channel = woOutput % 4 - } - - // Enable the port multiplexer for pin - pin.setPinCfg(sam.PORT_GROUP_PINCFG_PMUXEN) - - // Connect timer/mux to pin. - if pin&1 > 0 { - // odd pin, so save the even pins - val := pin.getPMux() & sam.PORT_GROUP_PMUX_PMUXE_Msk - pin.setPMux(val | uint8(pinMode<> 4) - dac.syncDAC() - return nil -} - -func (dac DAC) syncDAC() { - switch dac.Channel { - case 0: - for !sam.DAC.STATUS.HasBits(sam.DAC_STATUS_EOC0) { - } - for sam.DAC.SYNCBUSY.HasBits(sam.DAC_SYNCBUSY_DATA0) { - } - default: - for !sam.DAC.STATUS.HasBits(sam.DAC_STATUS_EOC1) { - } - for sam.DAC.SYNCBUSY.HasBits(sam.DAC_SYNCBUSY_DATA1) { - } - } -} - -// GetRNG returns 32 bits of cryptographically secure random data -func GetRNG() (uint32, error) { - if !sam.MCLK.APBCMASK.HasBits(sam.MCLK_APBCMASK_TRNG_) { - // Turn on clock for TRNG - sam.MCLK.APBCMASK.SetBits(sam.MCLK_APBCMASK_TRNG_) - - // enable - sam.TRNG.CTRLA.Set(sam.TRNG_CTRLA_ENABLE) - } - for !sam.TRNG.INTFLAG.HasBits(sam.TRNG_INTFLAG_DATARDY) { - } - ret := sam.TRNG.DATA.Get() - return ret, nil -} - -// Flash related code -const memoryStart = 0x0 - -// compile-time check for ensuring we fulfill BlockDevice interface -var _ BlockDevice = flashBlockDevice{} - -var Flash flashBlockDevice - -type flashBlockDevice struct { - initComplete bool -} - -// ReadAt reads the given number of bytes from the block device. -func (f flashBlockDevice) ReadAt(p []byte, off int64) (n int, err error) { - if FlashDataStart()+uintptr(off)+uintptr(len(p)) > FlashDataEnd() { - return 0, errFlashCannotReadPastEOF - } - - waitWhileFlashBusy() - - data := unsafe.Slice((*byte)(unsafe.Add(unsafe.Pointer(FlashDataStart()), uintptr(off))), len(p)) - copy(p, data) - - return len(p), nil -} - -// WriteAt writes the given number of bytes to the block device. -// Data is written to the page buffer in 4-byte chunks, then saved to flash memory. -// See SAM-D5x-E5x-Family-Data-Sheet-DS60001507.pdf page 591-592. -// If the length of p is not long enough it will be padded with 0xFF bytes. -// This method assumes that the destination is already erased. -func (f flashBlockDevice) WriteAt(p []byte, off int64) (n int, err error) { - if FlashDataStart()+uintptr(off)+uintptr(len(p)) > FlashDataEnd() { - return 0, errFlashCannotWritePastEOF - } - - address := FlashDataStart() + uintptr(off) - padded := flashPad(p, int(f.WriteBlockSize())) - - settings := disableFlashCache() - defer restoreFlashCache(settings) - - waitWhileFlashBusy() - - sam.NVMCTRL.CTRLB.Set(sam.NVMCTRL_CTRLB_CMD_PBC | (sam.NVMCTRL_CTRLB_CMDEX_KEY << sam.NVMCTRL_CTRLB_CMDEX_Pos)) - - waitWhileFlashBusy() - - for j := 0; j < len(padded); j += int(f.WriteBlockSize()) { - // page buffer is 512 bytes long, but only 4 bytes can be written at once - for k := 0; k < int(f.WriteBlockSize()); k += 4 { - *(*uint32)(unsafe.Pointer(address + uintptr(k))) = binary.LittleEndian.Uint32(padded[j+k : j+k+4]) - } - - sam.NVMCTRL.SetADDR(uint32(address)) - sam.NVMCTRL.CTRLB.Set(sam.NVMCTRL_CTRLB_CMD_WP | (sam.NVMCTRL_CTRLB_CMDEX_KEY << sam.NVMCTRL_CTRLB_CMDEX_Pos)) - - waitWhileFlashBusy() - - if err := checkFlashError(); err != nil { - return j, err - } - - address += uintptr(f.WriteBlockSize()) - } - - return len(padded), nil -} - -// Size returns the number of bytes in this block device. -func (f flashBlockDevice) Size() int64 { - return int64(FlashDataEnd() - FlashDataStart()) -} - -const writeBlockSize = 512 - -// WriteBlockSize returns the block size in which data can be written to -// memory. It can be used by a client to optimize writes, non-aligned writes -// should always work correctly. -func (f flashBlockDevice) WriteBlockSize() int64 { - return writeBlockSize -} - -const eraseBlockSizeValue = 8192 - -func eraseBlockSize() int64 { - return eraseBlockSizeValue -} - -// EraseBlockSize returns the smallest erasable area on this particular chip -// in bytes. This is used for the block size in EraseBlocks. -func (f flashBlockDevice) EraseBlockSize() int64 { - return eraseBlockSize() -} - -// EraseBlocks erases the given number of blocks. An implementation may -// transparently coalesce ranges of blocks into larger bundles if the chip -// supports this. The start and len parameters are in block numbers, use -// EraseBlockSize to map addresses to blocks. -func (f flashBlockDevice) EraseBlocks(start, len int64) error { - address := FlashDataStart() + uintptr(start*f.EraseBlockSize()) - - settings := disableFlashCache() - defer restoreFlashCache(settings) - - waitWhileFlashBusy() - - for i := start; i < start+len; i++ { - sam.NVMCTRL.SetADDR(uint32(address)) - sam.NVMCTRL.CTRLB.Set(sam.NVMCTRL_CTRLB_CMD_EB | (sam.NVMCTRL_CTRLB_CMDEX_KEY << sam.NVMCTRL_CTRLB_CMDEX_Pos)) - - waitWhileFlashBusy() - - if err := checkFlashError(); err != nil { - return err - } - - address += uintptr(f.EraseBlockSize()) - } - - return nil -} - -func disableFlashCache() uint16 { - settings := sam.NVMCTRL.CTRLA.Get() - - // disable caches - sam.NVMCTRL.SetCTRLA_CACHEDIS0(1) - sam.NVMCTRL.SetCTRLA_CACHEDIS1(1) - - waitWhileFlashBusy() - - return settings -} - -func restoreFlashCache(settings uint16) { - sam.NVMCTRL.CTRLA.Set(settings) - waitWhileFlashBusy() -} - -func waitWhileFlashBusy() { - for sam.NVMCTRL.GetSTATUS_READY() != sam.NVMCTRL_STATUS_READY { - } -} - -var ( - errFlashADDRE = errors.New("errFlashADDRE") - errFlashPROGE = errors.New("errFlashPROGE") - errFlashLOCKE = errors.New("errFlashLOCKE") - errFlashECCSE = errors.New("errFlashECCSE") - errFlashNVME = errors.New("errFlashNVME") - errFlashSEESOVF = errors.New("errFlashSEESOVF") -) - -func checkFlashError() error { - switch { - case sam.NVMCTRL.GetINTENSET_ADDRE() != 0: - return errFlashADDRE - case sam.NVMCTRL.GetINTENSET_PROGE() != 0: - return errFlashPROGE - case sam.NVMCTRL.GetINTENSET_LOCKE() != 0: - return errFlashLOCKE - case sam.NVMCTRL.GetINTENSET_ECCSE() != 0: - return errFlashECCSE - case sam.NVMCTRL.GetINTENSET_NVME() != 0: - return errFlashNVME - case sam.NVMCTRL.GetINTENSET_SEESOVF() != 0: - return errFlashSEESOVF - } - - return nil -} - -// Watchdog provides access to the hardware watchdog available -// in the SAMD51. -var Watchdog = &watchdogImpl{} - -const ( - // WatchdogMaxTimeout in milliseconds (16s) - WatchdogMaxTimeout = (16384 * 1000) / 1024 // CYC16384/1024kHz -) - -type watchdogImpl struct{} - -// Configure the watchdog. -// -// This method should not be called after the watchdog is started and on -// some platforms attempting to reconfigure after starting the watchdog -// is explicitly forbidden / will not work. -func (wd *watchdogImpl) Configure(config WatchdogConfig) error { - // 1.024kHz clock - cycles := int((int64(config.TimeoutMillis) * 1024) / 1000) - - // period is expressed as a power-of-two, starting at 8 / 1024ths of a second - period := uint8(0) - cfgCycles := 8 - for cfgCycles < cycles { - period++ - cfgCycles <<= 1 - - if period >= 0xB { - break - } - } - - sam.WDT.CONFIG.Set(period << sam.WDT_CONFIG_PER_Pos) - - return nil -} - -// Starts the watchdog. -func (wd *watchdogImpl) Start() error { - sam.WDT.CTRLA.SetBits(sam.WDT_CTRLA_ENABLE) - return nil -} - -// Update the watchdog, indicating that `source` is healthy. -func (wd *watchdogImpl) Update() { - sam.WDT.CLEAR.Set(sam.WDT_CLEAR_CLEAR_KEY) -} diff --git a/emb/machine/machine_atsamd51_usb.go b/emb/machine/machine_atsamd51_usb.go deleted file mode 100644 index a95089f..0000000 --- a/emb/machine/machine_atsamd51_usb.go +++ /dev/null @@ -1,495 +0,0 @@ -//go:build (sam && atsamd51) || (sam && atsame5x) - -package machine - -import ( - "device/sam" - "machine/usb" - "runtime/interrupt" - "unsafe" -) - -const ( - // these are SAMD51 specific. - usb_DEVICE_PCKSIZE_BYTE_COUNT_Pos = 0 - usb_DEVICE_PCKSIZE_BYTE_COUNT_Mask = 0x3FFF - - usb_DEVICE_PCKSIZE_SIZE_Pos = 28 - usb_DEVICE_PCKSIZE_SIZE_Mask = 0x7 - - usb_DEVICE_PCKSIZE_MULTI_PACKET_SIZE_Pos = 14 - usb_DEVICE_PCKSIZE_MULTI_PACKET_SIZE_Mask = 0x3FFF - - NumberOfUSBEndpoints = 8 -) - -var ( - endPoints = []uint32{ - usb.CONTROL_ENDPOINT: usb.ENDPOINT_TYPE_CONTROL, - usb.CDC_ENDPOINT_ACM: (usb.ENDPOINT_TYPE_INTERRUPT | usb.EndpointIn), - usb.CDC_ENDPOINT_OUT: (usb.ENDPOINT_TYPE_BULK | usb.EndpointOut), - usb.CDC_ENDPOINT_IN: (usb.ENDPOINT_TYPE_BULK | usb.EndpointIn), - usb.HID_ENDPOINT_IN: (usb.ENDPOINT_TYPE_DISABLE), // Interrupt In - usb.HID_ENDPOINT_OUT: (usb.ENDPOINT_TYPE_DISABLE), // Interrupt Out - usb.MIDI_ENDPOINT_IN: (usb.ENDPOINT_TYPE_DISABLE), // Bulk In - usb.MIDI_ENDPOINT_OUT: (usb.ENDPOINT_TYPE_DISABLE), // Bulk Out - } -) - -// Configure the USB peripheral. The config is here for compatibility with the UART interface. -func (dev *USBDevice) Configure(config UARTConfig) { - if dev.initcomplete { - return - } - - // reset USB interface - sam.USB_DEVICE.CTRLA.SetBits(sam.USB_DEVICE_CTRLA_SWRST) - for sam.USB_DEVICE.SYNCBUSY.HasBits(sam.USB_DEVICE_SYNCBUSY_SWRST) || - sam.USB_DEVICE.SYNCBUSY.HasBits(sam.USB_DEVICE_SYNCBUSY_ENABLE) { - } - - sam.USB_DEVICE.DESCADD.Set(uint32(uintptr(unsafe.Pointer(&usbEndpointDescriptors)))) - - // configure pins - USBCDC_DM_PIN.Configure(PinConfig{Mode: PinCom}) - USBCDC_DP_PIN.Configure(PinConfig{Mode: PinCom}) - - // performs pad calibration from store fuses - handlePadCalibration() - - // run in standby - sam.USB_DEVICE.CTRLA.SetBits(sam.USB_DEVICE_CTRLA_RUNSTDBY) - - // set full speed - sam.USB_DEVICE.CTRLB.SetBits(sam.USB_DEVICE_CTRLB_SPDCONF_FS << sam.USB_DEVICE_CTRLB_SPDCONF_Pos) - - // attach - sam.USB_DEVICE.CTRLB.ClearBits(sam.USB_DEVICE_CTRLB_DETACH) - - // enable interrupt for end of reset - sam.USB_DEVICE.INTENSET.SetBits(sam.USB_DEVICE_INTENSET_EORST) - - // enable interrupt for start of frame - sam.USB_DEVICE.INTENSET.SetBits(sam.USB_DEVICE_INTENSET_SOF) - - // enable USB - sam.USB_DEVICE.CTRLA.SetBits(sam.USB_DEVICE_CTRLA_ENABLE) - - // enable IRQ - interrupt.New(sam.IRQ_USB_OTHER, handleUSBIRQ).Enable() - interrupt.New(sam.IRQ_USB_SOF_HSOF, handleUSBIRQ).Enable() - interrupt.New(sam.IRQ_USB_TRCPT0, handleUSBIRQ).Enable() - interrupt.New(sam.IRQ_USB_TRCPT1, handleUSBIRQ).Enable() - - dev.initcomplete = true -} - -func handlePadCalibration() { - // Load Pad Calibration data from non-volatile memory - // This requires registers that are not included in the SVD file. - // Modeled after defines from samd21g18a.h and nvmctrl.h: - // - // #define NVMCTRL_OTP4 0x00806020 - // - // #define USB_FUSES_TRANSN_ADDR (NVMCTRL_OTP4 + 4) - // #define USB_FUSES_TRANSN_Pos 13 /**< \brief (NVMCTRL_OTP4) USB pad Transn calibration */ - // #define USB_FUSES_TRANSN_Msk (0x1Fu << USB_FUSES_TRANSN_Pos) - // #define USB_FUSES_TRANSN(value) ((USB_FUSES_TRANSN_Msk & ((value) << USB_FUSES_TRANSN_Pos))) - - // #define USB_FUSES_TRANSP_ADDR (NVMCTRL_OTP4 + 4) - // #define USB_FUSES_TRANSP_Pos 18 /**< \brief (NVMCTRL_OTP4) USB pad Transp calibration */ - // #define USB_FUSES_TRANSP_Msk (0x1Fu << USB_FUSES_TRANSP_Pos) - // #define USB_FUSES_TRANSP(value) ((USB_FUSES_TRANSP_Msk & ((value) << USB_FUSES_TRANSP_Pos))) - - // #define USB_FUSES_TRIM_ADDR (NVMCTRL_OTP4 + 4) - // #define USB_FUSES_TRIM_Pos 23 /**< \brief (NVMCTRL_OTP4) USB pad Trim calibration */ - // #define USB_FUSES_TRIM_Msk (0x7u << USB_FUSES_TRIM_Pos) - // #define USB_FUSES_TRIM(value) ((USB_FUSES_TRIM_Msk & ((value) << USB_FUSES_TRIM_Pos))) - // - fuse := *(*uint32)(unsafe.Pointer(uintptr(0x00806020) + 4)) - calibTransN := uint16(fuse>>13) & uint16(0x1f) - calibTransP := uint16(fuse>>18) & uint16(0x1f) - calibTrim := uint16(fuse>>23) & uint16(0x7) - - if calibTransN == 0x1f { - calibTransN = 5 - } - sam.USB_DEVICE.PADCAL.SetBits(calibTransN << sam.USB_DEVICE_PADCAL_TRANSN_Pos) - - if calibTransP == 0x1f { - calibTransP = 29 - } - sam.USB_DEVICE.PADCAL.SetBits(calibTransP << sam.USB_DEVICE_PADCAL_TRANSP_Pos) - - if calibTrim == 0x7 { - calibTrim = 3 - } - sam.USB_DEVICE.PADCAL.SetBits(calibTrim << sam.USB_DEVICE_PADCAL_TRIM_Pos) -} - -func handleUSBIRQ(intr interrupt.Interrupt) { - // reset all interrupt flags - flags := sam.USB_DEVICE.INTFLAG.Get() - sam.USB_DEVICE.INTFLAG.Set(flags) - - // End of reset - if (flags & sam.USB_DEVICE_INTFLAG_EORST) > 0 { - // Configure control endpoint - initEndpoint(0, usb.ENDPOINT_TYPE_CONTROL) - - usbConfiguration = 0 - - // ack the End-Of-Reset interrupt - sam.USB_DEVICE.INTFLAG.Set(sam.USB_DEVICE_INTFLAG_EORST) - } - - // Start of frame - if (flags & sam.USB_DEVICE_INTFLAG_SOF) > 0 { - // if you want to blink LED showing traffic, this would be the place... - } - - // Endpoint 0 Setup interrupt - if getEPINTFLAG(0)&sam.USB_DEVICE_ENDPOINT_EPINTFLAG_RXSTP > 0 { - // ack setup received - setEPINTFLAG(0, sam.USB_DEVICE_ENDPOINT_EPINTFLAG_RXSTP) - - // parse setup - setup := usb.NewSetup(udd_ep_out_cache_buffer[0][:]) - - // Clear the Bank 0 ready flag on Control OUT - usbEndpointDescriptors[0].DeviceDescBank[0].ADDR.Set(uint32(uintptr(unsafe.Pointer(&udd_ep_out_cache_buffer[0])))) - usbEndpointDescriptors[0].DeviceDescBank[0].PCKSIZE.ClearBits(usb_DEVICE_PCKSIZE_BYTE_COUNT_Mask << usb_DEVICE_PCKSIZE_BYTE_COUNT_Pos) - setEPSTATUSCLR(0, sam.USB_DEVICE_ENDPOINT_EPSTATUSCLR_BK0RDY) - - ok := false - if (setup.BmRequestType & usb.REQUEST_TYPE) == usb.REQUEST_STANDARD { - // Standard Requests - ok = handleStandardSetup(setup) - } else { - // Class Interface Requests - if setup.WIndex < uint16(len(usbSetupHandler)) && usbSetupHandler[setup.WIndex] != nil { - ok = usbSetupHandler[setup.WIndex](setup) - } - } - - if ok { - // set Bank1 ready - setEPSTATUSSET(0, sam.USB_DEVICE_ENDPOINT_EPSTATUSSET_BK1RDY) - } else { - // Stall endpoint - setEPSTATUSSET(0, sam.USB_DEVICE_ENDPOINT_EPINTFLAG_STALL1) - } - - if getEPINTFLAG(0)&sam.USB_DEVICE_ENDPOINT_EPINTFLAG_STALL1 > 0 { - // ack the stall - setEPINTFLAG(0, sam.USB_DEVICE_ENDPOINT_EPINTFLAG_STALL1) - - // clear stall request - setEPINTENCLR(0, sam.USB_DEVICE_ENDPOINT_EPINTENCLR_STALL1) - } - } - - // Now the actual transfer handlers, ignore endpoint number 0 (setup) - var i uint32 - for i = 1; i < uint32(len(endPoints)); i++ { - // Check if endpoint has a pending interrupt - epFlags := getEPINTFLAG(i) - setEPINTFLAG(i, epFlags) - if (epFlags & sam.USB_DEVICE_ENDPOINT_EPINTFLAG_TRCPT0) > 0 { - buf := handleEndpointRx(i) - if usbRxHandler[i] == nil || usbRxHandler[i](buf) { - AckUsbOutTransfer(i) - } - } else if (epFlags & sam.USB_DEVICE_ENDPOINT_EPINTFLAG_TRCPT1) > 0 { - if usbTxHandler[i] != nil { - usbTxHandler[i]() - } - } - } -} - -func initEndpoint(ep, config uint32) { - switch config { - case usb.ENDPOINT_TYPE_INTERRUPT | usb.EndpointIn: - // set packet size - usbEndpointDescriptors[ep].DeviceDescBank[1].PCKSIZE.SetBits(epPacketSize(64) << usb_DEVICE_PCKSIZE_SIZE_Pos) - - // set data buffer address - usbEndpointDescriptors[ep].DeviceDescBank[1].ADDR.Set(uint32(uintptr(unsafe.Pointer(&udd_ep_in_cache_buffer[ep])))) - - // set endpoint type - setEPCFG(ep, ((usb.ENDPOINT_TYPE_INTERRUPT + 1) << sam.USB_DEVICE_ENDPOINT_EPCFG_EPTYPE1_Pos)) - - setEPINTENSET(ep, sam.USB_DEVICE_ENDPOINT_EPINTENSET_TRCPT1) - - case usb.ENDPOINT_TYPE_BULK | usb.EndpointOut: - // set packet size - usbEndpointDescriptors[ep].DeviceDescBank[0].PCKSIZE.SetBits(epPacketSize(64) << usb_DEVICE_PCKSIZE_SIZE_Pos) - - // set data buffer address - usbEndpointDescriptors[ep].DeviceDescBank[0].ADDR.Set(uint32(uintptr(unsafe.Pointer(&udd_ep_out_cache_buffer[ep])))) - - // set endpoint type - setEPCFG(ep, ((usb.ENDPOINT_TYPE_BULK + 1) << sam.USB_DEVICE_ENDPOINT_EPCFG_EPTYPE0_Pos)) - - // receive interrupts when current transfer complete - setEPINTENSET(ep, sam.USB_DEVICE_ENDPOINT_EPINTENSET_TRCPT0) - - // set byte count to zero, we have not received anything yet - usbEndpointDescriptors[ep].DeviceDescBank[0].PCKSIZE.ClearBits(usb_DEVICE_PCKSIZE_BYTE_COUNT_Mask << usb_DEVICE_PCKSIZE_BYTE_COUNT_Pos) - - // ready for next transfer - setEPSTATUSCLR(ep, sam.USB_DEVICE_ENDPOINT_EPSTATUSCLR_BK0RDY) - - case usb.ENDPOINT_TYPE_INTERRUPT | usb.EndpointOut: - // set packet size - usbEndpointDescriptors[ep].DeviceDescBank[0].PCKSIZE.SetBits(epPacketSize(64) << usb_DEVICE_PCKSIZE_SIZE_Pos) - - // set data buffer address - usbEndpointDescriptors[ep].DeviceDescBank[0].ADDR.Set(uint32(uintptr(unsafe.Pointer(&udd_ep_out_cache_buffer[ep])))) - - // set endpoint type - setEPCFG(ep, ((usb.ENDPOINT_TYPE_INTERRUPT + 1) << sam.USB_DEVICE_ENDPOINT_EPCFG_EPTYPE0_Pos)) - - // receive interrupts when current transfer complete - setEPINTENSET(ep, sam.USB_DEVICE_ENDPOINT_EPINTENSET_TRCPT0) - - // set byte count to zero, we have not received anything yet - usbEndpointDescriptors[ep].DeviceDescBank[0].PCKSIZE.ClearBits(usb_DEVICE_PCKSIZE_BYTE_COUNT_Mask << usb_DEVICE_PCKSIZE_BYTE_COUNT_Pos) - - // ready for next transfer - setEPSTATUSCLR(ep, sam.USB_DEVICE_ENDPOINT_EPSTATUSCLR_BK0RDY) - - case usb.ENDPOINT_TYPE_BULK | usb.EndpointIn: - // set packet size - usbEndpointDescriptors[ep].DeviceDescBank[1].PCKSIZE.SetBits(epPacketSize(64) << usb_DEVICE_PCKSIZE_SIZE_Pos) - - // set data buffer address - usbEndpointDescriptors[ep].DeviceDescBank[1].ADDR.Set(uint32(uintptr(unsafe.Pointer(&udd_ep_in_cache_buffer[ep])))) - - // set endpoint type - setEPCFG(ep, ((usb.ENDPOINT_TYPE_BULK + 1) << sam.USB_DEVICE_ENDPOINT_EPCFG_EPTYPE1_Pos)) - - // NAK on endpoint IN, the bank is not yet filled in. - setEPSTATUSCLR(ep, sam.USB_DEVICE_ENDPOINT_EPSTATUSCLR_BK1RDY) - - setEPINTENSET(ep, sam.USB_DEVICE_ENDPOINT_EPINTENSET_TRCPT1) - - case usb.ENDPOINT_TYPE_CONTROL: - // Control OUT - // set packet size - usbEndpointDescriptors[ep].DeviceDescBank[0].PCKSIZE.SetBits(epPacketSize(64) << usb_DEVICE_PCKSIZE_SIZE_Pos) - - // set data buffer address - usbEndpointDescriptors[ep].DeviceDescBank[0].ADDR.Set(uint32(uintptr(unsafe.Pointer(&udd_ep_out_cache_buffer[ep])))) - - // set endpoint type - setEPCFG(ep, getEPCFG(ep)|((usb.ENDPOINT_TYPE_CONTROL+1)<> - usb_DEVICE_PCKSIZE_BYTE_COUNT_Pos) & usb_DEVICE_PCKSIZE_BYTE_COUNT_Mask) - - if bytesread != cdcLineInfoSize { - return b, ErrUSBBytesRead - } - - copy(b[:7], udd_ep_out_cache_buffer[0][:7]) - - return b, nil -} - -func handleEndpointRx(ep uint32) []byte { - // get data - count := int((usbEndpointDescriptors[ep].DeviceDescBank[0].PCKSIZE.Get() >> - usb_DEVICE_PCKSIZE_BYTE_COUNT_Pos) & usb_DEVICE_PCKSIZE_BYTE_COUNT_Mask) - - return udd_ep_out_cache_buffer[ep][:count] -} - -// AckUsbOutTransfer is called to acknowledge the completion of a USB OUT transfer. -func AckUsbOutTransfer(ep uint32) { - // set byte count to zero - usbEndpointDescriptors[ep].DeviceDescBank[0].PCKSIZE.ClearBits(usb_DEVICE_PCKSIZE_BYTE_COUNT_Mask << usb_DEVICE_PCKSIZE_BYTE_COUNT_Pos) - - // set multi packet size to 64 - usbEndpointDescriptors[ep].DeviceDescBank[0].PCKSIZE.SetBits(64 << usb_DEVICE_PCKSIZE_MULTI_PACKET_SIZE_Pos) - - // set ready for next data - setEPSTATUSCLR(ep, sam.USB_DEVICE_ENDPOINT_EPSTATUSCLR_BK0RDY) -} - -func SendZlp() { - usbEndpointDescriptors[0].DeviceDescBank[1].PCKSIZE.ClearBits(usb_DEVICE_PCKSIZE_BYTE_COUNT_Mask << usb_DEVICE_PCKSIZE_BYTE_COUNT_Pos) -} - -func epPacketSize(size uint16) uint32 { - switch size { - case 8: - return 0 - case 16: - return 1 - case 32: - return 2 - case 64: - return 3 - case 128: - return 4 - case 256: - return 5 - case 512: - return 6 - case 1023: - return 7 - default: - return 0 - } -} - -func getEPCFG(ep uint32) uint8 { - return sam.USB_DEVICE.DEVICE_ENDPOINT[ep].EPCFG.Get() -} - -func setEPCFG(ep uint32, val uint8) { - sam.USB_DEVICE.DEVICE_ENDPOINT[ep].EPCFG.Set(val) -} - -func setEPSTATUSCLR(ep uint32, val uint8) { - sam.USB_DEVICE.DEVICE_ENDPOINT[ep].EPSTATUSCLR.Set(val) -} - -func setEPSTATUSSET(ep uint32, val uint8) { - sam.USB_DEVICE.DEVICE_ENDPOINT[ep].EPSTATUSSET.Set(val) -} - -func getEPSTATUS(ep uint32) uint8 { - return sam.USB_DEVICE.DEVICE_ENDPOINT[ep].EPSTATUS.Get() -} - -func getEPINTFLAG(ep uint32) uint8 { - return sam.USB_DEVICE.DEVICE_ENDPOINT[ep].EPINTFLAG.Get() -} - -func setEPINTFLAG(ep uint32, val uint8) { - sam.USB_DEVICE.DEVICE_ENDPOINT[ep].EPINTFLAG.Set(val) -} - -func setEPINTENCLR(ep uint32, val uint8) { - sam.USB_DEVICE.DEVICE_ENDPOINT[ep].EPINTENCLR.Set(val) -} - -func setEPINTENSET(ep uint32, val uint8) { - sam.USB_DEVICE.DEVICE_ENDPOINT[ep].EPINTENSET.Set(val) -} diff --git a/emb/machine/machine_atsamd51g19.go b/emb/machine/machine_atsamd51g19.go deleted file mode 100644 index f223f6e..0000000 --- a/emb/machine/machine_atsamd51g19.go +++ /dev/null @@ -1,98 +0,0 @@ -//go:build sam && atsamd51 && atsamd51g19 - -// Peripheral abstraction layer for the atsamd51. -// -// Datasheet: -// http://ww1.microchip.com/downloads/en/DeviceDoc/60001507C.pdf -package machine - -import "device/sam" - -const HSRAM_SIZE = 0x00030000 - -var ( - sercomI2CM0 = &I2C{Bus: sam.SERCOM0_I2CM, SERCOM: 0} - sercomI2CM1 = &I2C{Bus: sam.SERCOM1_I2CM, SERCOM: 1} - sercomI2CM2 = &I2C{Bus: sam.SERCOM2_I2CM, SERCOM: 2} - sercomI2CM3 = &I2C{Bus: sam.SERCOM3_I2CM, SERCOM: 3} - sercomI2CM4 = &I2C{Bus: sam.SERCOM4_I2CM, SERCOM: 4} - sercomI2CM5 = &I2C{Bus: sam.SERCOM5_I2CM, SERCOM: 5} - - sercomSPIM0 = &SPI{Bus: sam.SERCOM0_SPIM, SERCOM: 0} - sercomSPIM1 = &SPI{Bus: sam.SERCOM1_SPIM, SERCOM: 1} - sercomSPIM2 = &SPI{Bus: sam.SERCOM2_SPIM, SERCOM: 2} - sercomSPIM3 = &SPI{Bus: sam.SERCOM3_SPIM, SERCOM: 3} - sercomSPIM4 = &SPI{Bus: sam.SERCOM4_SPIM, SERCOM: 4} - sercomSPIM5 = &SPI{Bus: sam.SERCOM5_SPIM, SERCOM: 5} -) - -// setSERCOMClockGenerator sets the GCLK for sercom -func setSERCOMClockGenerator(sercom uint8, gclk uint32) { - switch sercom { - case 0: - sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM0_CORE].ClearBits(sam.GCLK_PCHCTRL_CHEN) - sam.MCLK.APBAMASK.SetBits(sam.MCLK_APBAMASK_SERCOM0_) - sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM0_CORE].Set((gclk << sam.GCLK_PCHCTRL_GEN_Pos) | - sam.GCLK_PCHCTRL_CHEN) - case 1: - sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM1_CORE].ClearBits(sam.GCLK_PCHCTRL_CHEN) - sam.MCLK.APBAMASK.SetBits(sam.MCLK_APBAMASK_SERCOM1_) - sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM1_CORE].Set((gclk << sam.GCLK_PCHCTRL_GEN_Pos) | - sam.GCLK_PCHCTRL_CHEN) - case 2: - sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM2_CORE].ClearBits(sam.GCLK_PCHCTRL_CHEN) - sam.MCLK.APBBMASK.SetBits(sam.MCLK_APBBMASK_SERCOM2_) - sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM2_CORE].Set((gclk << sam.GCLK_PCHCTRL_GEN_Pos) | - sam.GCLK_PCHCTRL_CHEN) - case 3: - sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM3_CORE].ClearBits(sam.GCLK_PCHCTRL_CHEN) - sam.MCLK.APBBMASK.SetBits(sam.MCLK_APBBMASK_SERCOM3_) - sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM3_CORE].Set((gclk << sam.GCLK_PCHCTRL_GEN_Pos) | - sam.GCLK_PCHCTRL_CHEN) - case 4: - sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM4_CORE].ClearBits(sam.GCLK_PCHCTRL_CHEN) - sam.MCLK.APBDMASK.SetBits(sam.MCLK_APBDMASK_SERCOM4_) - sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM4_CORE].Set((gclk << sam.GCLK_PCHCTRL_GEN_Pos) | - sam.GCLK_PCHCTRL_CHEN) - case 5: - sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM5_CORE].ClearBits(sam.GCLK_PCHCTRL_CHEN) - sam.MCLK.APBDMASK.SetBits(sam.MCLK_APBDMASK_SERCOM5_) - sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM5_CORE].Set((gclk << sam.GCLK_PCHCTRL_GEN_Pos) | - sam.GCLK_PCHCTRL_CHEN) - } -} - -// This chip has three TCC peripherals, which have PWM as one feature. -var ( - TCC0 = (*TCC)(sam.TCC0) - TCC1 = (*TCC)(sam.TCC1) - TCC2 = (*TCC)(sam.TCC2) -) - -func (tcc *TCC) configureClock() { - // Turn on timer clocks used for TCC and use generic clock generator 0. - switch tcc.timer() { - case sam.TCC0: - sam.MCLK.APBBMASK.SetBits(sam.MCLK_APBBMASK_TCC0_) - sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_TCC0].Set((sam.GCLK_PCHCTRL_GEN_GCLK0 << sam.GCLK_PCHCTRL_GEN_Pos) | sam.GCLK_PCHCTRL_CHEN) - case sam.TCC1: - sam.MCLK.APBBMASK.SetBits(sam.MCLK_APBBMASK_TCC1_) - sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_TCC1].Set((sam.GCLK_PCHCTRL_GEN_GCLK0 << sam.GCLK_PCHCTRL_GEN_Pos) | sam.GCLK_PCHCTRL_CHEN) - case sam.TCC2: - sam.MCLK.APBCMASK.SetBits(sam.MCLK_APBCMASK_TCC2_) - sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_TCC2].Set((sam.GCLK_PCHCTRL_GEN_GCLK0 << sam.GCLK_PCHCTRL_GEN_Pos) | sam.GCLK_PCHCTRL_CHEN) - } -} - -func (tcc *TCC) timerNum() uint8 { - switch tcc.timer() { - case sam.TCC0: - return 0 - case sam.TCC1: - return 1 - case sam.TCC2: - return 2 - default: - return 0x0f // should not happen - } -} diff --git a/emb/machine/machine_atsamd51j19.go b/emb/machine/machine_atsamd51j19.go deleted file mode 100644 index 640e1ef..0000000 --- a/emb/machine/machine_atsamd51j19.go +++ /dev/null @@ -1,110 +0,0 @@ -//go:build sam && atsamd51 && atsamd51j19 - -// Peripheral abstraction layer for the atsamd51. -// -// Datasheet: -// http://ww1.microchip.com/downloads/en/DeviceDoc/SAM_D5xE5x_Family_Data_Sheet_DS60001507F.pdf -package machine - -import "device/sam" - -const HSRAM_SIZE = 0x00030000 - -var ( - sercomI2CM0 = &I2C{Bus: sam.SERCOM0_I2CM, SERCOM: 0} - sercomI2CM1 = &I2C{Bus: sam.SERCOM1_I2CM, SERCOM: 1} - sercomI2CM2 = &I2C{Bus: sam.SERCOM2_I2CM, SERCOM: 2} - sercomI2CM3 = &I2C{Bus: sam.SERCOM3_I2CM, SERCOM: 3} - sercomI2CM4 = &I2C{Bus: sam.SERCOM4_I2CM, SERCOM: 4} - sercomI2CM5 = &I2C{Bus: sam.SERCOM5_I2CM, SERCOM: 5} - - sercomSPIM0 = &SPI{Bus: sam.SERCOM0_SPIM, SERCOM: 0} - sercomSPIM1 = &SPI{Bus: sam.SERCOM1_SPIM, SERCOM: 1} - sercomSPIM2 = &SPI{Bus: sam.SERCOM2_SPIM, SERCOM: 2} - sercomSPIM3 = &SPI{Bus: sam.SERCOM3_SPIM, SERCOM: 3} - sercomSPIM4 = &SPI{Bus: sam.SERCOM4_SPIM, SERCOM: 4} - sercomSPIM5 = &SPI{Bus: sam.SERCOM5_SPIM, SERCOM: 5} -) - -// setSERCOMClockGenerator sets the GCLK for sercom -func setSERCOMClockGenerator(sercom uint8, gclk uint32) { - switch sercom { - case 0: - sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM0_CORE].ClearBits(sam.GCLK_PCHCTRL_CHEN) - sam.MCLK.APBAMASK.SetBits(sam.MCLK_APBAMASK_SERCOM0_) - sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM0_CORE].Set((gclk << sam.GCLK_PCHCTRL_GEN_Pos) | - sam.GCLK_PCHCTRL_CHEN) - case 1: - sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM1_CORE].ClearBits(sam.GCLK_PCHCTRL_CHEN) - sam.MCLK.APBAMASK.SetBits(sam.MCLK_APBAMASK_SERCOM1_) - sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM1_CORE].Set((gclk << sam.GCLK_PCHCTRL_GEN_Pos) | - sam.GCLK_PCHCTRL_CHEN) - case 2: - sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM2_CORE].ClearBits(sam.GCLK_PCHCTRL_CHEN) - sam.MCLK.APBBMASK.SetBits(sam.MCLK_APBBMASK_SERCOM2_) - sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM2_CORE].Set((gclk << sam.GCLK_PCHCTRL_GEN_Pos) | - sam.GCLK_PCHCTRL_CHEN) - case 3: - sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM3_CORE].ClearBits(sam.GCLK_PCHCTRL_CHEN) - sam.MCLK.APBBMASK.SetBits(sam.MCLK_APBBMASK_SERCOM3_) - sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM3_CORE].Set((gclk << sam.GCLK_PCHCTRL_GEN_Pos) | - sam.GCLK_PCHCTRL_CHEN) - case 4: - sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM4_CORE].ClearBits(sam.GCLK_PCHCTRL_CHEN) - sam.MCLK.APBDMASK.SetBits(sam.MCLK_APBDMASK_SERCOM4_) - sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM4_CORE].Set((gclk << sam.GCLK_PCHCTRL_GEN_Pos) | - sam.GCLK_PCHCTRL_CHEN) - case 5: - sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM5_CORE].ClearBits(sam.GCLK_PCHCTRL_CHEN) - sam.MCLK.APBDMASK.SetBits(sam.MCLK_APBDMASK_SERCOM5_) - sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM5_CORE].Set((gclk << sam.GCLK_PCHCTRL_GEN_Pos) | - sam.GCLK_PCHCTRL_CHEN) - } -} - -// This chip has five TCC peripherals, which have PWM as one feature. -var ( - TCC0 = (*TCC)(sam.TCC0) - TCC1 = (*TCC)(sam.TCC1) - TCC2 = (*TCC)(sam.TCC2) - TCC3 = (*TCC)(sam.TCC3) - TCC4 = (*TCC)(sam.TCC4) -) - -func (tcc *TCC) configureClock() { - // Turn on timer clocks used for the TCC and use generic clock generator 0. - switch tcc.timer() { - case sam.TCC0: - sam.MCLK.APBBMASK.SetBits(sam.MCLK_APBBMASK_TCC0_) - sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_TCC0].Set((sam.GCLK_PCHCTRL_GEN_GCLK0 << sam.GCLK_PCHCTRL_GEN_Pos) | sam.GCLK_PCHCTRL_CHEN) - case sam.TCC1: - sam.MCLK.APBBMASK.SetBits(sam.MCLK_APBBMASK_TCC1_) - sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_TCC1].Set((sam.GCLK_PCHCTRL_GEN_GCLK0 << sam.GCLK_PCHCTRL_GEN_Pos) | sam.GCLK_PCHCTRL_CHEN) - case sam.TCC2: - sam.MCLK.APBCMASK.SetBits(sam.MCLK_APBCMASK_TCC2_) - sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_TCC2].Set((sam.GCLK_PCHCTRL_GEN_GCLK0 << sam.GCLK_PCHCTRL_GEN_Pos) | sam.GCLK_PCHCTRL_CHEN) - case sam.TCC3: - sam.MCLK.APBCMASK.SetBits(sam.MCLK_APBCMASK_TCC3_) - sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_TCC3].Set((sam.GCLK_PCHCTRL_GEN_GCLK0 << sam.GCLK_PCHCTRL_GEN_Pos) | sam.GCLK_PCHCTRL_CHEN) - case sam.TCC4: - sam.MCLK.APBDMASK.SetBits(sam.MCLK_APBDMASK_TCC4_) - sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_TCC4].Set((sam.GCLK_PCHCTRL_GEN_GCLK0 << sam.GCLK_PCHCTRL_GEN_Pos) | sam.GCLK_PCHCTRL_CHEN) - } -} - -func (tcc *TCC) timerNum() uint8 { - switch tcc.timer() { - case sam.TCC0: - return 0 - case sam.TCC1: - return 1 - case sam.TCC2: - return 2 - case sam.TCC3: - return 3 - case sam.TCC4: - return 4 - default: - return 0x0f // should not happen - } -} diff --git a/emb/machine/machine_atsamd51j20.go b/emb/machine/machine_atsamd51j20.go deleted file mode 100644 index d582278..0000000 --- a/emb/machine/machine_atsamd51j20.go +++ /dev/null @@ -1,110 +0,0 @@ -//go:build sam && atsamd51 && atsamd51j20 - -// Peripheral abstraction layer for the atsamd51. -// -// Datasheet: -// http://ww1.microchip.com/downloads/en/DeviceDoc/60001507C.pdf -package machine - -import "device/sam" - -const HSRAM_SIZE = 0x00040000 - -var ( - sercomI2CM0 = &I2C{Bus: sam.SERCOM0_I2CM, SERCOM: 0} - sercomI2CM1 = &I2C{Bus: sam.SERCOM1_I2CM, SERCOM: 1} - sercomI2CM2 = &I2C{Bus: sam.SERCOM2_I2CM, SERCOM: 2} - sercomI2CM3 = &I2C{Bus: sam.SERCOM3_I2CM, SERCOM: 3} - sercomI2CM4 = &I2C{Bus: sam.SERCOM4_I2CM, SERCOM: 4} - sercomI2CM5 = &I2C{Bus: sam.SERCOM5_I2CM, SERCOM: 5} - - sercomSPIM0 = &SPI{Bus: sam.SERCOM0_SPIM, SERCOM: 0} - sercomSPIM1 = &SPI{Bus: sam.SERCOM1_SPIM, SERCOM: 1} - sercomSPIM2 = &SPI{Bus: sam.SERCOM2_SPIM, SERCOM: 2} - sercomSPIM3 = &SPI{Bus: sam.SERCOM3_SPIM, SERCOM: 3} - sercomSPIM4 = &SPI{Bus: sam.SERCOM4_SPIM, SERCOM: 4} - sercomSPIM5 = &SPI{Bus: sam.SERCOM5_SPIM, SERCOM: 5} -) - -// setSERCOMClockGenerator sets the GCLK for sercom -func setSERCOMClockGenerator(sercom uint8, gclk uint32) { - switch sercom { - case 0: - sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM0_CORE].ClearBits(sam.GCLK_PCHCTRL_CHEN) - sam.MCLK.APBAMASK.SetBits(sam.MCLK_APBAMASK_SERCOM0_) - sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM0_CORE].Set((gclk << sam.GCLK_PCHCTRL_GEN_Pos) | - sam.GCLK_PCHCTRL_CHEN) - case 1: - sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM1_CORE].ClearBits(sam.GCLK_PCHCTRL_CHEN) - sam.MCLK.APBAMASK.SetBits(sam.MCLK_APBAMASK_SERCOM1_) - sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM1_CORE].Set((gclk << sam.GCLK_PCHCTRL_GEN_Pos) | - sam.GCLK_PCHCTRL_CHEN) - case 2: - sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM2_CORE].ClearBits(sam.GCLK_PCHCTRL_CHEN) - sam.MCLK.APBBMASK.SetBits(sam.MCLK_APBBMASK_SERCOM2_) - sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM2_CORE].Set((gclk << sam.GCLK_PCHCTRL_GEN_Pos) | - sam.GCLK_PCHCTRL_CHEN) - case 3: - sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM3_CORE].ClearBits(sam.GCLK_PCHCTRL_CHEN) - sam.MCLK.APBBMASK.SetBits(sam.MCLK_APBBMASK_SERCOM3_) - sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM3_CORE].Set((gclk << sam.GCLK_PCHCTRL_GEN_Pos) | - sam.GCLK_PCHCTRL_CHEN) - case 4: - sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM4_CORE].ClearBits(sam.GCLK_PCHCTRL_CHEN) - sam.MCLK.APBDMASK.SetBits(sam.MCLK_APBDMASK_SERCOM4_) - sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM4_CORE].Set((gclk << sam.GCLK_PCHCTRL_GEN_Pos) | - sam.GCLK_PCHCTRL_CHEN) - case 5: - sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM5_CORE].ClearBits(sam.GCLK_PCHCTRL_CHEN) - sam.MCLK.APBDMASK.SetBits(sam.MCLK_APBDMASK_SERCOM5_) - sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM5_CORE].Set((gclk << sam.GCLK_PCHCTRL_GEN_Pos) | - sam.GCLK_PCHCTRL_CHEN) - } -} - -// This chip has five TCC peripherals, which have PWM as one feature. -var ( - TCC0 = (*TCC)(sam.TCC0) - TCC1 = (*TCC)(sam.TCC1) - TCC2 = (*TCC)(sam.TCC2) - TCC3 = (*TCC)(sam.TCC3) - TCC4 = (*TCC)(sam.TCC4) -) - -func (tcc *TCC) configureClock() { - // Turn on timer clocks used for TCC and use generic clock generator 0. - switch tcc.timer() { - case sam.TCC0: - sam.MCLK.APBBMASK.SetBits(sam.MCLK_APBBMASK_TCC0_) - sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_TCC0].Set((sam.GCLK_PCHCTRL_GEN_GCLK0 << sam.GCLK_PCHCTRL_GEN_Pos) | sam.GCLK_PCHCTRL_CHEN) - case sam.TCC1: - sam.MCLK.APBBMASK.SetBits(sam.MCLK_APBBMASK_TCC1_) - sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_TCC1].Set((sam.GCLK_PCHCTRL_GEN_GCLK0 << sam.GCLK_PCHCTRL_GEN_Pos) | sam.GCLK_PCHCTRL_CHEN) - case sam.TCC2: - sam.MCLK.APBCMASK.SetBits(sam.MCLK_APBCMASK_TCC2_) - sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_TCC2].Set((sam.GCLK_PCHCTRL_GEN_GCLK0 << sam.GCLK_PCHCTRL_GEN_Pos) | sam.GCLK_PCHCTRL_CHEN) - case sam.TCC3: - sam.MCLK.APBCMASK.SetBits(sam.MCLK_APBCMASK_TCC3_) - sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_TCC3].Set((sam.GCLK_PCHCTRL_GEN_GCLK0 << sam.GCLK_PCHCTRL_GEN_Pos) | sam.GCLK_PCHCTRL_CHEN) - case sam.TCC4: - sam.MCLK.APBDMASK.SetBits(sam.MCLK_APBDMASK_TCC4_) - sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_TCC4].Set((sam.GCLK_PCHCTRL_GEN_GCLK0 << sam.GCLK_PCHCTRL_GEN_Pos) | sam.GCLK_PCHCTRL_CHEN) - } -} - -func (tcc *TCC) timerNum() uint8 { - switch tcc.timer() { - case sam.TCC0: - return 0 - case sam.TCC1: - return 1 - case sam.TCC2: - return 2 - case sam.TCC3: - return 3 - case sam.TCC4: - return 4 - default: - return 0x0f // should not happen - } -} diff --git a/emb/machine/machine_atsamd51p19.go b/emb/machine/machine_atsamd51p19.go deleted file mode 100644 index bcd66a9..0000000 --- a/emb/machine/machine_atsamd51p19.go +++ /dev/null @@ -1,124 +0,0 @@ -//go:build sam && atsamd51 && atsamd51p19 - -// Peripheral abstraction layer for the atsamd51. -// -// Datasheet: -// http://ww1.microchip.com/downloads/en/DeviceDoc/60001507C.pdf -package machine - -import "device/sam" - -const HSRAM_SIZE = 0x00030000 - -var ( - sercomI2CM0 = &I2C{Bus: sam.SERCOM0_I2CM, SERCOM: 0} - sercomI2CM1 = &I2C{Bus: sam.SERCOM1_I2CM, SERCOM: 1} - sercomI2CM2 = &I2C{Bus: sam.SERCOM2_I2CM, SERCOM: 2} - sercomI2CM3 = &I2C{Bus: sam.SERCOM3_I2CM, SERCOM: 3} - sercomI2CM4 = &I2C{Bus: sam.SERCOM4_I2CM, SERCOM: 4} - sercomI2CM5 = &I2C{Bus: sam.SERCOM5_I2CM, SERCOM: 5} - sercomI2CM6 = &I2C{Bus: sam.SERCOM6_I2CM, SERCOM: 6} - sercomI2CM7 = &I2C{Bus: sam.SERCOM7_I2CM, SERCOM: 7} - - sercomSPIM0 = &SPI{Bus: sam.SERCOM0_SPIM, SERCOM: 0} - sercomSPIM1 = &SPI{Bus: sam.SERCOM1_SPIM, SERCOM: 1} - sercomSPIM2 = &SPI{Bus: sam.SERCOM2_SPIM, SERCOM: 2} - sercomSPIM3 = &SPI{Bus: sam.SERCOM3_SPIM, SERCOM: 3} - sercomSPIM4 = &SPI{Bus: sam.SERCOM4_SPIM, SERCOM: 4} - sercomSPIM5 = &SPI{Bus: sam.SERCOM5_SPIM, SERCOM: 5} - sercomSPIM6 = &SPI{Bus: sam.SERCOM6_SPIM, SERCOM: 6} - sercomSPIM7 = &SPI{Bus: sam.SERCOM7_SPIM, SERCOM: 7} -) - -// setSERCOMClockGenerator sets the GCLK for sercom -func setSERCOMClockGenerator(sercom uint8, gclk uint32) { - switch sercom { - case 0: - sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM0_CORE].ClearBits(sam.GCLK_PCHCTRL_CHEN) - sam.MCLK.APBAMASK.SetBits(sam.MCLK_APBAMASK_SERCOM0_) - sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM0_CORE].Set((gclk << sam.GCLK_PCHCTRL_GEN_Pos) | - sam.GCLK_PCHCTRL_CHEN) - case 1: - sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM1_CORE].ClearBits(sam.GCLK_PCHCTRL_CHEN) - sam.MCLK.APBAMASK.SetBits(sam.MCLK_APBAMASK_SERCOM1_) - sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM1_CORE].Set((gclk << sam.GCLK_PCHCTRL_GEN_Pos) | - sam.GCLK_PCHCTRL_CHEN) - case 2: - sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM2_CORE].ClearBits(sam.GCLK_PCHCTRL_CHEN) - sam.MCLK.APBBMASK.SetBits(sam.MCLK_APBBMASK_SERCOM2_) - sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM2_CORE].Set((gclk << sam.GCLK_PCHCTRL_GEN_Pos) | - sam.GCLK_PCHCTRL_CHEN) - case 3: - sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM3_CORE].ClearBits(sam.GCLK_PCHCTRL_CHEN) - sam.MCLK.APBBMASK.SetBits(sam.MCLK_APBBMASK_SERCOM3_) - sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM3_CORE].Set((gclk << sam.GCLK_PCHCTRL_GEN_Pos) | - sam.GCLK_PCHCTRL_CHEN) - case 4: - sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM4_CORE].ClearBits(sam.GCLK_PCHCTRL_CHEN) - sam.MCLK.APBDMASK.SetBits(sam.MCLK_APBDMASK_SERCOM4_) - sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM4_CORE].Set((gclk << sam.GCLK_PCHCTRL_GEN_Pos) | - sam.GCLK_PCHCTRL_CHEN) - case 5: - sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM5_CORE].ClearBits(sam.GCLK_PCHCTRL_CHEN) - sam.MCLK.APBDMASK.SetBits(sam.MCLK_APBDMASK_SERCOM5_) - sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM5_CORE].Set((gclk << sam.GCLK_PCHCTRL_GEN_Pos) | - sam.GCLK_PCHCTRL_CHEN) - case 6: - sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM6_CORE].ClearBits(sam.GCLK_PCHCTRL_CHEN) - sam.MCLK.APBDMASK.SetBits(sam.MCLK_APBDMASK_SERCOM6_) - sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM6_CORE].Set((gclk << sam.GCLK_PCHCTRL_GEN_Pos) | - sam.GCLK_PCHCTRL_CHEN) - case 7: - sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM7_CORE].ClearBits(sam.GCLK_PCHCTRL_CHEN) - sam.MCLK.APBDMASK.SetBits(sam.MCLK_APBDMASK_SERCOM7_) - sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM7_CORE].Set((gclk << sam.GCLK_PCHCTRL_GEN_Pos) | - sam.GCLK_PCHCTRL_CHEN) - } -} - -// This chip has five TCC peripherals, which have PWM as one feature. -var ( - TCC0 = (*TCC)(sam.TCC0) - TCC1 = (*TCC)(sam.TCC1) - TCC2 = (*TCC)(sam.TCC2) - TCC3 = (*TCC)(sam.TCC3) - TCC4 = (*TCC)(sam.TCC4) -) - -func (tcc *TCC) configureClock() { - // Turn on timer clocks used for TCC and use generic clock generator 0. - switch tcc.timer() { - case sam.TCC0: - sam.MCLK.APBBMASK.SetBits(sam.MCLK_APBBMASK_TCC0_) - sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_TCC0].Set((sam.GCLK_PCHCTRL_GEN_GCLK0 << sam.GCLK_PCHCTRL_GEN_Pos) | sam.GCLK_PCHCTRL_CHEN) - case sam.TCC1: - sam.MCLK.APBBMASK.SetBits(sam.MCLK_APBBMASK_TCC1_) - sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_TCC1].Set((sam.GCLK_PCHCTRL_GEN_GCLK0 << sam.GCLK_PCHCTRL_GEN_Pos) | sam.GCLK_PCHCTRL_CHEN) - case sam.TCC2: - sam.MCLK.APBCMASK.SetBits(sam.MCLK_APBCMASK_TCC2_) - sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_TCC2].Set((sam.GCLK_PCHCTRL_GEN_GCLK0 << sam.GCLK_PCHCTRL_GEN_Pos) | sam.GCLK_PCHCTRL_CHEN) - case sam.TCC3: - sam.MCLK.APBCMASK.SetBits(sam.MCLK_APBCMASK_TCC3_) - sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_TCC3].Set((sam.GCLK_PCHCTRL_GEN_GCLK0 << sam.GCLK_PCHCTRL_GEN_Pos) | sam.GCLK_PCHCTRL_CHEN) - case sam.TCC4: - sam.MCLK.APBDMASK.SetBits(sam.MCLK_APBDMASK_TCC4_) - sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_TCC4].Set((sam.GCLK_PCHCTRL_GEN_GCLK0 << sam.GCLK_PCHCTRL_GEN_Pos) | sam.GCLK_PCHCTRL_CHEN) - } -} - -func (tcc *TCC) timerNum() uint8 { - switch tcc.timer() { - case sam.TCC0: - return 0 - case sam.TCC1: - return 1 - case sam.TCC2: - return 2 - case sam.TCC3: - return 3 - case sam.TCC4: - return 4 - default: - return 0x0f // should not happen - } -} diff --git a/emb/machine/machine_atsamd51p20.go b/emb/machine/machine_atsamd51p20.go deleted file mode 100644 index 40e435f..0000000 --- a/emb/machine/machine_atsamd51p20.go +++ /dev/null @@ -1,124 +0,0 @@ -//go:build sam && atsamd51 && atsamd51p20 - -// Peripheral abstraction layer for the atsamd51. -// -// Datasheet: -// http://ww1.microchip.com/downloads/en/DeviceDoc/60001507C.pdf -package machine - -import "device/sam" - -const HSRAM_SIZE = 0x00040000 - -var ( - sercomI2CM0 = &I2C{Bus: sam.SERCOM0_I2CM, SERCOM: 0} - sercomI2CM1 = &I2C{Bus: sam.SERCOM1_I2CM, SERCOM: 1} - sercomI2CM2 = &I2C{Bus: sam.SERCOM2_I2CM, SERCOM: 2} - sercomI2CM3 = &I2C{Bus: sam.SERCOM3_I2CM, SERCOM: 3} - sercomI2CM4 = &I2C{Bus: sam.SERCOM4_I2CM, SERCOM: 4} - sercomI2CM5 = &I2C{Bus: sam.SERCOM5_I2CM, SERCOM: 5} - sercomI2CM6 = &I2C{Bus: sam.SERCOM6_I2CM, SERCOM: 6} - sercomI2CM7 = &I2C{Bus: sam.SERCOM7_I2CM, SERCOM: 7} - - sercomSPIM0 = &SPI{Bus: sam.SERCOM0_SPIM, SERCOM: 0} - sercomSPIM1 = &SPI{Bus: sam.SERCOM1_SPIM, SERCOM: 1} - sercomSPIM2 = &SPI{Bus: sam.SERCOM2_SPIM, SERCOM: 2} - sercomSPIM3 = &SPI{Bus: sam.SERCOM3_SPIM, SERCOM: 3} - sercomSPIM4 = &SPI{Bus: sam.SERCOM4_SPIM, SERCOM: 4} - sercomSPIM5 = &SPI{Bus: sam.SERCOM5_SPIM, SERCOM: 5} - sercomSPIM6 = &SPI{Bus: sam.SERCOM6_SPIM, SERCOM: 6} - sercomSPIM7 = &SPI{Bus: sam.SERCOM7_SPIM, SERCOM: 7} -) - -// setSERCOMClockGenerator sets the GCLK for sercom -func setSERCOMClockGenerator(sercom uint8, gclk uint32) { - switch sercom { - case 0: - sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM0_CORE].ClearBits(sam.GCLK_PCHCTRL_CHEN) - sam.MCLK.APBAMASK.SetBits(sam.MCLK_APBAMASK_SERCOM0_) - sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM0_CORE].Set((gclk << sam.GCLK_PCHCTRL_GEN_Pos) | - sam.GCLK_PCHCTRL_CHEN) - case 1: - sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM1_CORE].ClearBits(sam.GCLK_PCHCTRL_CHEN) - sam.MCLK.APBAMASK.SetBits(sam.MCLK_APBAMASK_SERCOM1_) - sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM1_CORE].Set((gclk << sam.GCLK_PCHCTRL_GEN_Pos) | - sam.GCLK_PCHCTRL_CHEN) - case 2: - sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM2_CORE].ClearBits(sam.GCLK_PCHCTRL_CHEN) - sam.MCLK.APBBMASK.SetBits(sam.MCLK_APBBMASK_SERCOM2_) - sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM2_CORE].Set((gclk << sam.GCLK_PCHCTRL_GEN_Pos) | - sam.GCLK_PCHCTRL_CHEN) - case 3: - sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM3_CORE].ClearBits(sam.GCLK_PCHCTRL_CHEN) - sam.MCLK.APBBMASK.SetBits(sam.MCLK_APBBMASK_SERCOM3_) - sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM3_CORE].Set((gclk << sam.GCLK_PCHCTRL_GEN_Pos) | - sam.GCLK_PCHCTRL_CHEN) - case 4: - sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM4_CORE].ClearBits(sam.GCLK_PCHCTRL_CHEN) - sam.MCLK.APBDMASK.SetBits(sam.MCLK_APBDMASK_SERCOM4_) - sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM4_CORE].Set((gclk << sam.GCLK_PCHCTRL_GEN_Pos) | - sam.GCLK_PCHCTRL_CHEN) - case 5: - sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM5_CORE].ClearBits(sam.GCLK_PCHCTRL_CHEN) - sam.MCLK.APBDMASK.SetBits(sam.MCLK_APBDMASK_SERCOM5_) - sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM5_CORE].Set((gclk << sam.GCLK_PCHCTRL_GEN_Pos) | - sam.GCLK_PCHCTRL_CHEN) - case 6: - sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM6_CORE].ClearBits(sam.GCLK_PCHCTRL_CHEN) - sam.MCLK.APBDMASK.SetBits(sam.MCLK_APBDMASK_SERCOM6_) - sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM6_CORE].Set((gclk << sam.GCLK_PCHCTRL_GEN_Pos) | - sam.GCLK_PCHCTRL_CHEN) - case 7: - sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM7_CORE].ClearBits(sam.GCLK_PCHCTRL_CHEN) - sam.MCLK.APBDMASK.SetBits(sam.MCLK_APBDMASK_SERCOM7_) - sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM7_CORE].Set((gclk << sam.GCLK_PCHCTRL_GEN_Pos) | - sam.GCLK_PCHCTRL_CHEN) - } -} - -// This chip has five TCC peripherals, which have PWM as one feature. -var ( - TCC0 = (*TCC)(sam.TCC0) - TCC1 = (*TCC)(sam.TCC1) - TCC2 = (*TCC)(sam.TCC2) - TCC3 = (*TCC)(sam.TCC3) - TCC4 = (*TCC)(sam.TCC4) -) - -func (tcc *TCC) configureClock() { - // Turn on timer clocks used for TCC and use generic clock generator 0. - switch tcc.timer() { - case sam.TCC0: - sam.MCLK.APBBMASK.SetBits(sam.MCLK_APBBMASK_TCC0_) - sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_TCC0].Set((sam.GCLK_PCHCTRL_GEN_GCLK0 << sam.GCLK_PCHCTRL_GEN_Pos) | sam.GCLK_PCHCTRL_CHEN) - case sam.TCC1: - sam.MCLK.APBBMASK.SetBits(sam.MCLK_APBBMASK_TCC1_) - sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_TCC1].Set((sam.GCLK_PCHCTRL_GEN_GCLK0 << sam.GCLK_PCHCTRL_GEN_Pos) | sam.GCLK_PCHCTRL_CHEN) - case sam.TCC2: - sam.MCLK.APBCMASK.SetBits(sam.MCLK_APBCMASK_TCC2_) - sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_TCC2].Set((sam.GCLK_PCHCTRL_GEN_GCLK0 << sam.GCLK_PCHCTRL_GEN_Pos) | sam.GCLK_PCHCTRL_CHEN) - case sam.TCC3: - sam.MCLK.APBCMASK.SetBits(sam.MCLK_APBCMASK_TCC3_) - sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_TCC3].Set((sam.GCLK_PCHCTRL_GEN_GCLK0 << sam.GCLK_PCHCTRL_GEN_Pos) | sam.GCLK_PCHCTRL_CHEN) - case sam.TCC4: - sam.MCLK.APBDMASK.SetBits(sam.MCLK_APBDMASK_TCC4_) - sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_TCC4].Set((sam.GCLK_PCHCTRL_GEN_GCLK0 << sam.GCLK_PCHCTRL_GEN_Pos) | sam.GCLK_PCHCTRL_CHEN) - } -} - -func (tcc *TCC) timerNum() uint8 { - switch tcc.timer() { - case sam.TCC0: - return 0 - case sam.TCC1: - return 1 - case sam.TCC2: - return 2 - case sam.TCC3: - return 3 - case sam.TCC4: - return 4 - default: - return 0x0f // should not happen - } -} diff --git a/emb/machine/machine_atsame51j19.go b/emb/machine/machine_atsame51j19.go deleted file mode 100644 index 29ea411..0000000 --- a/emb/machine/machine_atsame51j19.go +++ /dev/null @@ -1,110 +0,0 @@ -//go:build sam && atsame51 && atsame51j19 - -// Peripheral abstraction layer for the atsame51. -// -// Datasheet: -// http://ww1.microchip.com/downloads/en/DeviceDoc/SAM_D5xE5x_Family_Data_Sheet_DS60001507F.pdf -package machine - -import "device/sam" - -const HSRAM_SIZE = 0x00030000 - -var ( - sercomI2CM0 = &I2C{Bus: sam.SERCOM0_I2CM, SERCOM: 0} - sercomI2CM1 = &I2C{Bus: sam.SERCOM1_I2CM, SERCOM: 1} - sercomI2CM2 = &I2C{Bus: sam.SERCOM2_I2CM, SERCOM: 2} - sercomI2CM3 = &I2C{Bus: sam.SERCOM3_I2CM, SERCOM: 3} - sercomI2CM4 = &I2C{Bus: sam.SERCOM4_I2CM, SERCOM: 4} - sercomI2CM5 = &I2C{Bus: sam.SERCOM5_I2CM, SERCOM: 5} - - sercomSPIM0 = &SPI{Bus: sam.SERCOM0_SPIM, SERCOM: 0} - sercomSPIM1 = &SPI{Bus: sam.SERCOM1_SPIM, SERCOM: 1} - sercomSPIM2 = &SPI{Bus: sam.SERCOM2_SPIM, SERCOM: 2} - sercomSPIM3 = &SPI{Bus: sam.SERCOM3_SPIM, SERCOM: 3} - sercomSPIM4 = &SPI{Bus: sam.SERCOM4_SPIM, SERCOM: 4} - sercomSPIM5 = &SPI{Bus: sam.SERCOM5_SPIM, SERCOM: 5} -) - -// setSERCOMClockGenerator sets the GCLK for sercom -func setSERCOMClockGenerator(sercom uint8, gclk uint32) { - switch sercom { - case 0: - sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM0_CORE].ClearBits(sam.GCLK_PCHCTRL_CHEN) - sam.MCLK.APBAMASK.SetBits(sam.MCLK_APBAMASK_SERCOM0_) - sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM0_CORE].Set((gclk << sam.GCLK_PCHCTRL_GEN_Pos) | - sam.GCLK_PCHCTRL_CHEN) - case 1: - sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM1_CORE].ClearBits(sam.GCLK_PCHCTRL_CHEN) - sam.MCLK.APBAMASK.SetBits(sam.MCLK_APBAMASK_SERCOM1_) - sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM1_CORE].Set((gclk << sam.GCLK_PCHCTRL_GEN_Pos) | - sam.GCLK_PCHCTRL_CHEN) - case 2: - sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM2_CORE].ClearBits(sam.GCLK_PCHCTRL_CHEN) - sam.MCLK.APBBMASK.SetBits(sam.MCLK_APBBMASK_SERCOM2_) - sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM2_CORE].Set((gclk << sam.GCLK_PCHCTRL_GEN_Pos) | - sam.GCLK_PCHCTRL_CHEN) - case 3: - sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM3_CORE].ClearBits(sam.GCLK_PCHCTRL_CHEN) - sam.MCLK.APBBMASK.SetBits(sam.MCLK_APBBMASK_SERCOM3_) - sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM3_CORE].Set((gclk << sam.GCLK_PCHCTRL_GEN_Pos) | - sam.GCLK_PCHCTRL_CHEN) - case 4: - sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM4_CORE].ClearBits(sam.GCLK_PCHCTRL_CHEN) - sam.MCLK.APBDMASK.SetBits(sam.MCLK_APBDMASK_SERCOM4_) - sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM4_CORE].Set((gclk << sam.GCLK_PCHCTRL_GEN_Pos) | - sam.GCLK_PCHCTRL_CHEN) - case 5: - sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM5_CORE].ClearBits(sam.GCLK_PCHCTRL_CHEN) - sam.MCLK.APBDMASK.SetBits(sam.MCLK_APBDMASK_SERCOM5_) - sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM5_CORE].Set((gclk << sam.GCLK_PCHCTRL_GEN_Pos) | - sam.GCLK_PCHCTRL_CHEN) - } -} - -// This chip has five TCC peripherals, which have PWM as one feature. -var ( - TCC0 = (*TCC)(sam.TCC0) - TCC1 = (*TCC)(sam.TCC1) - TCC2 = (*TCC)(sam.TCC2) - TCC3 = (*TCC)(sam.TCC3) - TCC4 = (*TCC)(sam.TCC4) -) - -func (tcc *TCC) configureClock() { - // Turn on timer clocks used for the TCC and use generic clock generator 0. - switch tcc.timer() { - case sam.TCC0: - sam.MCLK.APBBMASK.SetBits(sam.MCLK_APBBMASK_TCC0_) - sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_TCC0].Set((sam.GCLK_PCHCTRL_GEN_GCLK0 << sam.GCLK_PCHCTRL_GEN_Pos) | sam.GCLK_PCHCTRL_CHEN) - case sam.TCC1: - sam.MCLK.APBBMASK.SetBits(sam.MCLK_APBBMASK_TCC1_) - sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_TCC1].Set((sam.GCLK_PCHCTRL_GEN_GCLK0 << sam.GCLK_PCHCTRL_GEN_Pos) | sam.GCLK_PCHCTRL_CHEN) - case sam.TCC2: - sam.MCLK.APBCMASK.SetBits(sam.MCLK_APBCMASK_TCC2_) - sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_TCC2].Set((sam.GCLK_PCHCTRL_GEN_GCLK0 << sam.GCLK_PCHCTRL_GEN_Pos) | sam.GCLK_PCHCTRL_CHEN) - case sam.TCC3: - sam.MCLK.APBCMASK.SetBits(sam.MCLK_APBCMASK_TCC3_) - sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_TCC3].Set((sam.GCLK_PCHCTRL_GEN_GCLK0 << sam.GCLK_PCHCTRL_GEN_Pos) | sam.GCLK_PCHCTRL_CHEN) - case sam.TCC4: - sam.MCLK.APBDMASK.SetBits(sam.MCLK_APBDMASK_TCC4_) - sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_TCC4].Set((sam.GCLK_PCHCTRL_GEN_GCLK0 << sam.GCLK_PCHCTRL_GEN_Pos) | sam.GCLK_PCHCTRL_CHEN) - } -} - -func (tcc *TCC) timerNum() uint8 { - switch tcc.timer() { - case sam.TCC0: - return 0 - case sam.TCC1: - return 1 - case sam.TCC2: - return 2 - case sam.TCC3: - return 3 - case sam.TCC4: - return 4 - default: - return 0x0f // should not happen - } -} diff --git a/emb/machine/machine_atsame54p20.go b/emb/machine/machine_atsame54p20.go deleted file mode 100644 index d7cc31f..0000000 --- a/emb/machine/machine_atsame54p20.go +++ /dev/null @@ -1,124 +0,0 @@ -//go:build sam && atsame5x && atsame54p20 - -// Peripheral abstraction layer for the atsame54. -// -// Datasheet: -// http://ww1.microchip.com/downloads/en/DeviceDoc/60001507C.pdf -package machine - -import "device/sam" - -const HSRAM_SIZE = 0x00040000 - -var ( - sercomI2CM0 = &I2C{Bus: sam.SERCOM0_I2CM, SERCOM: 0} - sercomI2CM1 = &I2C{Bus: sam.SERCOM1_I2CM, SERCOM: 1} - sercomI2CM2 = &I2C{Bus: sam.SERCOM2_I2CM, SERCOM: 2} - sercomI2CM3 = &I2C{Bus: sam.SERCOM3_I2CM, SERCOM: 3} - sercomI2CM4 = &I2C{Bus: sam.SERCOM4_I2CM, SERCOM: 4} - sercomI2CM5 = &I2C{Bus: sam.SERCOM5_I2CM, SERCOM: 5} - sercomI2CM6 = &I2C{Bus: sam.SERCOM6_I2CM, SERCOM: 6} - sercomI2CM7 = &I2C{Bus: sam.SERCOM7_I2CM, SERCOM: 7} - - sercomSPIM0 = &SPI{Bus: sam.SERCOM0_SPIM, SERCOM: 0} - sercomSPIM1 = &SPI{Bus: sam.SERCOM1_SPIM, SERCOM: 1} - sercomSPIM2 = &SPI{Bus: sam.SERCOM2_SPIM, SERCOM: 2} - sercomSPIM3 = &SPI{Bus: sam.SERCOM3_SPIM, SERCOM: 3} - sercomSPIM4 = &SPI{Bus: sam.SERCOM4_SPIM, SERCOM: 4} - sercomSPIM5 = &SPI{Bus: sam.SERCOM5_SPIM, SERCOM: 5} - sercomSPIM6 = &SPI{Bus: sam.SERCOM6_SPIM, SERCOM: 6} - sercomSPIM7 = &SPI{Bus: sam.SERCOM7_SPIM, SERCOM: 7} -) - -// setSERCOMClockGenerator sets the GCLK for sercom -func setSERCOMClockGenerator(sercom uint8, gclk uint32) { - switch sercom { - case 0: - sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM0_CORE].ClearBits(sam.GCLK_PCHCTRL_CHEN) - sam.MCLK.APBAMASK.SetBits(sam.MCLK_APBAMASK_SERCOM0_) - sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM0_CORE].Set((gclk << sam.GCLK_PCHCTRL_GEN_Pos) | - sam.GCLK_PCHCTRL_CHEN) - case 1: - sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM1_CORE].ClearBits(sam.GCLK_PCHCTRL_CHEN) - sam.MCLK.APBAMASK.SetBits(sam.MCLK_APBAMASK_SERCOM1_) - sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM1_CORE].Set((gclk << sam.GCLK_PCHCTRL_GEN_Pos) | - sam.GCLK_PCHCTRL_CHEN) - case 2: - sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM2_CORE].ClearBits(sam.GCLK_PCHCTRL_CHEN) - sam.MCLK.APBBMASK.SetBits(sam.MCLK_APBBMASK_SERCOM2_) - sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM2_CORE].Set((gclk << sam.GCLK_PCHCTRL_GEN_Pos) | - sam.GCLK_PCHCTRL_CHEN) - case 3: - sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM3_CORE].ClearBits(sam.GCLK_PCHCTRL_CHEN) - sam.MCLK.APBBMASK.SetBits(sam.MCLK_APBBMASK_SERCOM3_) - sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM3_CORE].Set((gclk << sam.GCLK_PCHCTRL_GEN_Pos) | - sam.GCLK_PCHCTRL_CHEN) - case 4: - sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM4_CORE].ClearBits(sam.GCLK_PCHCTRL_CHEN) - sam.MCLK.APBDMASK.SetBits(sam.MCLK_APBDMASK_SERCOM4_) - sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM4_CORE].Set((gclk << sam.GCLK_PCHCTRL_GEN_Pos) | - sam.GCLK_PCHCTRL_CHEN) - case 5: - sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM5_CORE].ClearBits(sam.GCLK_PCHCTRL_CHEN) - sam.MCLK.APBDMASK.SetBits(sam.MCLK_APBDMASK_SERCOM5_) - sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM5_CORE].Set((gclk << sam.GCLK_PCHCTRL_GEN_Pos) | - sam.GCLK_PCHCTRL_CHEN) - case 6: - sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM6_CORE].ClearBits(sam.GCLK_PCHCTRL_CHEN) - sam.MCLK.APBDMASK.SetBits(sam.MCLK_APBDMASK_SERCOM6_) - sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM6_CORE].Set((gclk << sam.GCLK_PCHCTRL_GEN_Pos) | - sam.GCLK_PCHCTRL_CHEN) - case 7: - sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM7_CORE].ClearBits(sam.GCLK_PCHCTRL_CHEN) - sam.MCLK.APBDMASK.SetBits(sam.MCLK_APBDMASK_SERCOM7_) - sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM7_CORE].Set((gclk << sam.GCLK_PCHCTRL_GEN_Pos) | - sam.GCLK_PCHCTRL_CHEN) - } -} - -// This chip has five TCC peripherals, which have PWM as one feature. -var ( - TCC0 = (*TCC)(sam.TCC0) - TCC1 = (*TCC)(sam.TCC1) - TCC2 = (*TCC)(sam.TCC2) - TCC3 = (*TCC)(sam.TCC3) - TCC4 = (*TCC)(sam.TCC4) -) - -func (tcc *TCC) configureClock() { - // Turn on timer clocks used for TCC and use generic clock generator 0. - switch tcc.timer() { - case sam.TCC0: - sam.MCLK.APBBMASK.SetBits(sam.MCLK_APBBMASK_TCC0_) - sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_TCC0].Set((sam.GCLK_PCHCTRL_GEN_GCLK0 << sam.GCLK_PCHCTRL_GEN_Pos) | sam.GCLK_PCHCTRL_CHEN) - case sam.TCC1: - sam.MCLK.APBBMASK.SetBits(sam.MCLK_APBBMASK_TCC1_) - sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_TCC1].Set((sam.GCLK_PCHCTRL_GEN_GCLK0 << sam.GCLK_PCHCTRL_GEN_Pos) | sam.GCLK_PCHCTRL_CHEN) - case sam.TCC2: - sam.MCLK.APBCMASK.SetBits(sam.MCLK_APBCMASK_TCC2_) - sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_TCC2].Set((sam.GCLK_PCHCTRL_GEN_GCLK0 << sam.GCLK_PCHCTRL_GEN_Pos) | sam.GCLK_PCHCTRL_CHEN) - case sam.TCC3: - sam.MCLK.APBCMASK.SetBits(sam.MCLK_APBCMASK_TCC3_) - sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_TCC3].Set((sam.GCLK_PCHCTRL_GEN_GCLK0 << sam.GCLK_PCHCTRL_GEN_Pos) | sam.GCLK_PCHCTRL_CHEN) - case sam.TCC4: - sam.MCLK.APBDMASK.SetBits(sam.MCLK_APBDMASK_TCC4_) - sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_TCC4].Set((sam.GCLK_PCHCTRL_GEN_GCLK0 << sam.GCLK_PCHCTRL_GEN_Pos) | sam.GCLK_PCHCTRL_CHEN) - } -} - -func (tcc *TCC) timerNum() uint8 { - switch tcc.timer() { - case sam.TCC0: - return 0 - case sam.TCC1: - return 1 - case sam.TCC2: - return 2 - case sam.TCC3: - return 3 - case sam.TCC4: - return 4 - default: - return 0x0f // should not happen - } -} diff --git a/emb/machine/machine_atsame5x_can.go b/emb/machine/machine_atsame5x_can.go deleted file mode 100644 index bf38cd8..0000000 --- a/emb/machine/machine_atsame5x_can.go +++ /dev/null @@ -1,478 +0,0 @@ -//go:build (sam && atsame51) || (sam && atsame54) - -package machine - -import ( - "device/sam" - "errors" - "runtime/interrupt" - "unsafe" -) - -const ( - CANRxFifoSize = 16 - CANTxFifoSize = 16 - CANEvFifoSize = 16 -) - -// Message RAM can only be located in the first 64 KB area of the system RAM. -// TODO: when the go:section pragma is merged, add the section configuration - -//go:align 4 -var CANRxFifo [2][(8 + 64) * CANRxFifoSize]byte - -//go:align 4 -var CANTxFifo [2][(8 + 64) * CANTxFifoSize]byte - -//go:align 4 -var CANEvFifo [2][(8) * CANEvFifoSize]byte - -type CAN struct { - Bus *sam.CAN_Type -} - -type CANTransferRate uint32 - -// CAN transfer rates for CANConfig -const ( - CANTransferRate125kbps CANTransferRate = 125000 - CANTransferRate250kbps CANTransferRate = 250000 - CANTransferRate500kbps CANTransferRate = 500000 - CANTransferRate1000kbps CANTransferRate = 1000000 - CANTransferRate2000kbps CANTransferRate = 2000000 - CANTransferRate4000kbps CANTransferRate = 4000000 -) - -// CANConfig holds CAN configuration parameters. Tx and Rx need to be -// specified with some pins. When the Standby Pin is specified, configure it -// as an output pin and output Low in Configure(). If this operation is not -// necessary, specify NoPin. -type CANConfig struct { - TransferRate CANTransferRate - TransferRateFD CANTransferRate - Tx Pin - Rx Pin - Standby Pin -} - -var ( - errCANInvalidTransferRate = errors.New("CAN: invalid TransferRate") - errCANInvalidTransferRateFD = errors.New("CAN: invalid TransferRateFD") -) - -// Configure this CAN peripheral with the given configuration. -func (can *CAN) Configure(config CANConfig) error { - if config.Standby != NoPin { - config.Standby.Configure(PinConfig{Mode: PinOutput}) - config.Standby.Low() - } - - mode := PinCAN0 - if can.instance() == 1 { - mode = PinCAN1 - } - - config.Rx.Configure(PinConfig{Mode: mode}) - config.Tx.Configure(PinConfig{Mode: mode}) - - can.Bus.CCCR.SetBits(sam.CAN_CCCR_INIT) - for !can.Bus.CCCR.HasBits(sam.CAN_CCCR_INIT) { - } - - can.Bus.CCCR.SetBits(sam.CAN_CCCR_CCE) - - can.Bus.CCCR.SetBits(sam.CAN_CCCR_BRSE | sam.CAN_CCCR_FDOE) - can.Bus.MRCFG.Set(sam.CAN_MRCFG_QOS_MEDIUM) - // base clock == 48 MHz - if config.TransferRate == 0 { - config.TransferRate = CANTransferRate500kbps - } - brp := uint32(6) - switch config.TransferRate { - case CANTransferRate125kbps: - brp = 32 - case CANTransferRate250kbps: - brp = 16 - case CANTransferRate500kbps: - brp = 8 - case CANTransferRate1000kbps: - brp = 4 - default: - return errCANInvalidTransferRate - } - can.Bus.NBTP.Set(8<> sam.CAN_TXFQS_TFQPI_Pos - - f := CANTxFifo[can.instance()][putIndex*(8+64) : (putIndex+1)*(8+64)] - id := e.ID - if !e.XTD { - // standard identifier is stored into ID[28:18] - id <<= 18 - } - - f[3] = byte(id>>24) & 0x1F - if e.ESI { - f[3] |= 0x80 - } - if e.XTD { - f[3] |= 0x40 - } - if e.RTR { - f[3] |= 0x20 - } - f[2] = byte(id >> 16) - f[1] = byte(id >> 8) - f[0] = byte(id) - f[7] = e.MM - f[6] = e.DLC - if e.EFC { - f[6] |= 0x80 - } - if e.FDF { - f[6] |= 0x20 - } - if e.BRS { - f[6] |= 0x10 - } - f[5] = 0x00 // reserved - f[4] = 0x00 // reserved - - length := CANDlcToLength(e.DLC, e.FDF) - for i := byte(0); i < length; i++ { - f[8+i] = e.DB[i] - } - - can.Bus.TXBAR.SetBits(1 << putIndex) -} - -// The Tx transmits CAN frames. It is easier to use than TxRaw, but not as -// flexible. -func (can *CAN) Tx(id uint32, data []byte, isFD, isExtendedID bool) { - length := byte(len(data)) - dlc := CANLengthToDlc(length, true) - - e := CANTxBufferElement{ - ESI: false, - XTD: isExtendedID, - RTR: false, - ID: id, - MM: 0x00, - EFC: true, - FDF: isFD, - BRS: isFD, - DLC: dlc, - } - - if !isFD { - if length > 8 { - length = 8 - } - } - for i := byte(0); i < length; i++ { - e.DB[i] = data[i] - } - - can.TxRaw(&e) -} - -// RxFifoSize returns the number of CAN Frames currently stored in the RXFifo. -func (can *CAN) RxFifoSize() int { - sz := (can.Bus.RXF0S.Get() & sam.CAN_RXF0S_F0FL_Msk) >> sam.CAN_RXF0S_F0FL_Pos - return int(sz) -} - -// RxFifoIsFull returns whether RxFifo is full or not. -func (can *CAN) RxFifoIsFull() bool { - sz := (can.Bus.RXF0S.Get() & sam.CAN_RXF0S_F0FL_Msk) >> sam.CAN_RXF0S_F0FL_Pos - return sz == CANRxFifoSize -} - -// RxFifoIsEmpty returns whether RxFifo is empty or not. -func (can *CAN) RxFifoIsEmpty() bool { - sz := (can.Bus.RXF0S.Get() & sam.CAN_RXF0S_F0FL_Msk) >> sam.CAN_RXF0S_F0FL_Pos - return sz == 0 -} - -// RxRaw copies the received CAN frame to CANRxBufferElement. -func (can *CAN) RxRaw(e *CANRxBufferElement) { - idx := (can.Bus.RXF0S.Get() & sam.CAN_RXF0S_F0GI_Msk) >> sam.CAN_RXF0S_F0GI_Pos - f := CANRxFifo[can.instance()][idx*(8+64):] - - e.ESI = false - if (f[3] & 0x80) != 0x00 { - e.ESI = true - } - - e.XTD = false - if (f[3] & 0x40) != 0x00 { - e.XTD = true - } - - e.RTR = false - if (f[3] & 0x20) != 0x00 { - e.RTR = true - } - - id := ((uint32(f[3]) << 24) + (uint32(f[2]) << 16) + (uint32(f[1]) << 8) + uint32(f[0])) & 0x1FFFFFFF - if !e.XTD { - id >>= 18 - id &= 0x000007FF - } - e.ID = id - - e.ANMF = false - if (f[7] & 0x80) != 0x00 { - e.ANMF = true - } - - e.FIDX = f[7] & 0x7F - - e.FDF = false - if (f[6] & 0x20) != 0x00 { - e.FDF = true - } - - e.BRS = false - if (f[6] & 0x10) != 0x00 { - e.BRS = true - } - - e.DLC = f[6] & 0x0F - - e.RXTS = (uint16(f[5]) << 8) + uint16(f[4]) - - for i := byte(0); i < CANDlcToLength(e.DLC, e.FDF); i++ { - e.DB[i] = f[i+8] - } - - can.Bus.RXF0A.ReplaceBits(idx, sam.CAN_RXF0A_F0AI_Msk, sam.CAN_RXF0A_F0AI_Pos) -} - -// Rx receives a CAN frame. It is easier to use than RxRaw, but not as -// flexible. -func (can *CAN) Rx() (id uint32, dlc byte, data []byte, isFd, isExtendedID bool) { - e := CANRxBufferElement{} - can.RxRaw(&e) - length := CANDlcToLength(e.DLC, e.FDF) - return e.ID, length, e.DB[:length], e.FDF, e.XTD -} - -func (can *CAN) instance() byte { - if can.Bus == sam.CAN0 { - return 0 - } else { - return 1 - } -} - -// CANTxBufferElement is a struct that corresponds to the same5x' Tx Buffer -// Element. -type CANTxBufferElement struct { - ESI bool - XTD bool - RTR bool - ID uint32 - MM uint8 - EFC bool - FDF bool - BRS bool - DLC uint8 - DB [64]uint8 -} - -// CANRxBufferElement is a struct that corresponds to the same5x Rx Buffer and -// FIFO Element. -type CANRxBufferElement struct { - ESI bool - XTD bool - RTR bool - ID uint32 - ANMF bool - FIDX uint8 - FDF bool - BRS bool - DLC uint8 - RXTS uint16 - DB [64]uint8 -} - -// Data returns the received data as a slice of the size according to dlc. -func (e CANRxBufferElement) Data() []byte { - return e.DB[:CANDlcToLength(e.DLC, e.FDF)] -} - -// Length returns its actual length. -func (e CANRxBufferElement) Length() byte { - return CANDlcToLength(e.DLC, e.FDF) -} - -// CANDlcToLength() converts a DLC value to its actual length. -func CANDlcToLength(dlc byte, isFD bool) byte { - length := dlc - if dlc == 0x09 { - length = 12 - } else if dlc == 0x0A { - length = 16 - } else if dlc == 0x0B { - length = 20 - } else if dlc == 0x0C { - length = 24 - } else if dlc == 0x0D { - length = 32 - } else if dlc == 0x0E { - length = 48 - } else if dlc == 0x0F { - length = 64 - } - return length - -} - -// CANLengthToDlc() converts its actual length to a DLC value. -func CANLengthToDlc(length byte, isFD bool) byte { - dlc := length - if length <= 0x08 { - } else if length <= 12 { - dlc = 0x09 - } else if length <= 16 { - dlc = 0x0A - } else if length <= 20 { - dlc = 0x0B - } else if length <= 24 { - dlc = 0x0C - } else if length <= 32 { - dlc = 0x0D - } else if length <= 48 { - dlc = 0x0E - } else if length <= 64 { - dlc = 0x0F - } - return dlc -} diff --git a/emb/machine/machine_attiny1616.go b/emb/machine/machine_attiny1616.go deleted file mode 100644 index 55007ab..0000000 --- a/emb/machine/machine_attiny1616.go +++ /dev/null @@ -1,52 +0,0 @@ -//go:build attiny1616 - -package machine - -import ( - "device/avr" -) - -const ( - portA Pin = iota * 8 - portB - portC -) - -const ( - PA0 = portA + 0 - PA1 = portA + 1 - PA2 = portA + 2 - PA3 = portA + 3 - PA4 = portA + 4 - PA5 = portA + 5 - PA6 = portA + 6 - PA7 = portA + 7 - PB0 = portB + 0 - PB1 = portB + 1 - PB2 = portB + 2 - PB3 = portB + 3 - PB4 = portB + 4 - PB5 = portB + 5 - PB6 = portB + 6 - PB7 = portB + 7 - PC0 = portC + 0 - PC1 = portC + 1 - PC2 = portC + 2 - PC3 = portC + 3 - PC4 = portC + 4 - PC5 = portC + 5 - PC6 = portC + 6 - PC7 = portC + 7 -) - -// getPortMask returns the PORT peripheral and mask for the pin. -func (p Pin) getPortMask() (*avr.PORT_Type, uint8) { - switch { - case p >= PA0 && p <= PA7: // port A - return avr.PORTA, 1 << uint8(p-portA) - case p >= PB0 && p <= PB7: // port B - return avr.PORTB, 1 << uint8(p-portB) - default: // port C - return avr.PORTC, 1 << uint8(p-portC) - } -} diff --git a/emb/machine/machine_attiny85.go b/emb/machine/machine_attiny85.go deleted file mode 100644 index 33424c6..0000000 --- a/emb/machine/machine_attiny85.go +++ /dev/null @@ -1,23 +0,0 @@ -//go:build attiny85 - -package machine - -import ( - "device/avr" - "runtime/volatile" -) - -const ( - PB0 Pin = iota - PB1 - PB2 - PB3 - PB4 - PB5 -) - -// getPortMask returns the PORTx register and mask for the pin. -func (p Pin) getPortMask() (*volatile.Register8, uint8) { - // Very simple for the attiny85, which only has a single port. - return avr.PORTB, 1 << uint8(p) -} diff --git a/emb/machine/machine_avr.go b/emb/machine/machine_avr.go deleted file mode 100644 index 75252c3..0000000 --- a/emb/machine/machine_avr.go +++ /dev/null @@ -1,150 +0,0 @@ -//go:build avr && !avrtiny - -package machine - -import ( - "device/avr" - "runtime/volatile" - "unsafe" -) - -const deviceName = avr.DEVICE - -const ( - PinInput PinMode = iota - PinInputPullup - PinOutput -) - -// In all the AVRs I've looked at, the PIN/DDR/PORT registers followed a regular -// pattern: PINx, DDRx, PORTx in this order without registers in between. -// Therefore, if you know any of them, you can calculate the other two. -// -// For now, I've chosen to let the PORTx register be the one that is returned -// for each specific chip and to calculate the others from that one. Setting an -// output port (done using PORTx) is likely the most common operation and the -// one that is the most time critical. For others, the PINx and DDRx register -// can trivially be calculated using a subtraction. - -// Configure sets the pin to input or output. -func (p Pin) Configure(config PinConfig) { - port, mask := p.getPortMask() - // The DDRx register can be found by subtracting one from the PORTx - // register, as this appears to be the case for many (most? all?) AVR chips. - ddr := (*volatile.Register8)(unsafe.Pointer(uintptr(unsafe.Pointer(port)) - 1)) - if config.Mode == PinOutput { - // set output bit - ddr.SetBits(mask) - - // Note: if the pin was PinInputPullup before, it'll now be high. - // Otherwise it will be low. - } else { - // configure input: clear output bit - ddr.ClearBits(mask) - - if config.Mode == PinInput { - // No pullup (floating). - // The transition may be one of the following: - // output high -> input pullup -> input (safe: output high and input pullup are similar) - // output low -> input -> input (safe: no extra transition) - port.ClearBits(mask) - } else { - // Pullup. - // The transition may be one of the following: - // output high -> input pullup -> input pullup (safe: no extra transition) - // output low -> input -> input pullup (possibly problematic) - // For the last transition (output low -> input -> input pullup), - // the transition may be problematic in some cases because there is - // an intermediate floating state (which may cause irratic - // interrupts, for example). If this is a problem, the application - // should set the pin high before configuring it as PinInputPullup. - // We can't do that here because setting it to high as an - // intermediate state may have other problems. - port.SetBits(mask) - } - } -} - -// Get returns the current value of a GPIO pin when the pin is configured as an -// input or as an output. -func (p Pin) Get() bool { - port, mask := p.getPortMask() - // As noted above, the PINx register is always two registers below the PORTx - // register, so we can find it simply by subtracting two from the PORTx - // register address. - pin := (*volatile.Register8)(unsafe.Pointer(uintptr(unsafe.Pointer(port)) - 2)) // PINA, PINB, etc - return (pin.Get() & mask) > 0 -} - -// Set changes the value of the GPIO pin. The pin must be configured as output. -func (p Pin) Set(value bool) { - if value { // set bits - port, mask := p.PortMaskSet() - port.Set(mask) - } else { // clear bits - port, mask := p.PortMaskClear() - port.Set(mask) - } -} - -// Return the register and mask to enable a given GPIO pin. This can be used to -// implement bit-banged drivers. -// -// Warning: there are no separate pin set/clear registers on the AVR. The -// returned mask is only valid as long as no other pin in the same port has been -// changed. -func (p Pin) PortMaskSet() (*volatile.Register8, uint8) { - port, mask := p.getPortMask() - return port, port.Get() | mask -} - -// Return the register and mask to disable a given port. This can be used to -// implement bit-banged drivers. -// -// Warning: there are no separate pin set/clear registers on the AVR. The -// returned mask is only valid as long as no other pin in the same port has been -// changed. -func (p Pin) PortMaskClear() (*volatile.Register8, uint8) { - port, mask := p.getPortMask() - return port, port.Get() &^ mask -} - -// InitADC initializes the registers needed for ADC. -func InitADC() { - // set a2d prescaler so we are inside the desired 50-200 KHz range at 16MHz. - avr.ADCSRA.SetBits(avr.ADCSRA_ADPS2 | avr.ADCSRA_ADPS1 | avr.ADCSRA_ADPS0) - - // enable a2d conversions - avr.ADCSRA.SetBits(avr.ADCSRA_ADEN) -} - -// Configure configures a ADCPin to be able to be used to read data. -func (a ADC) Configure(ADCConfig) { - return // no pin specific setup on AVR machine. -} - -// Get returns the current value of a ADC pin, in the range 0..0xffff. The AVR -// has an ADC of 10 bits precision so the lower 6 bits will be zero. -func (a ADC) Get() uint16 { - // set the analog reference (high two bits of ADMUX) and select the - // channel (low 4 bits), masked to only turn on one ADC at a time. - // set the ADLAR bit (left-adjusted result) to get a value scaled to 16 - // bits. This has the same effect as shifting the return value left by 6 - // bits. - avr.ADMUX.Set(avr.ADMUX_REFS0 | avr.ADMUX_ADLAR | (uint8(a.Pin) & 0x07)) - - // start the conversion - avr.ADCSRA.SetBits(avr.ADCSRA_ADSC) - - // ADSC is cleared when the conversion finishes - for ok := true; ok; ok = avr.ADCSRA.HasBits(avr.ADCSRA_ADSC) { - } - - return uint16(avr.ADCL.Get()) | uint16(avr.ADCH.Get())<<8 -} - -// linked from runtime.adjustMonotonicTimer -func adjustMonotonicTimer() - -// linked from runtime.initMonotonicTimer -func initMonotonicTimer() diff --git a/emb/machine/machine_avrtiny.go b/emb/machine/machine_avrtiny.go deleted file mode 100644 index 78168f4..0000000 --- a/emb/machine/machine_avrtiny.go +++ /dev/null @@ -1,62 +0,0 @@ -//go:build avrtiny - -package machine - -import ( - "device/avr" - "runtime/volatile" - "unsafe" -) - -const deviceName = avr.DEVICE - -const ( - PinInput PinMode = iota - PinInputPullup - PinOutput -) - -// Configure sets the pin to input or output. -func (p Pin) Configure(config PinConfig) { - port, mask := p.getPortMask() - - if config.Mode == PinOutput { - // set output bit - port.DIRSET.Set(mask) - - // Note: the output state (high or low) is as it was before. - } else { - // Configure the pin as an input. - // First set up the configuration that will be used when it is an input. - pinctrl := uint8(0) - if config.Mode == PinInputPullup { - pinctrl |= avr.PORT_PIN0CTRL_PULLUPEN - } - // Find the PINxCTRL register for this pin. - ctrlAddress := (*volatile.Register8)(unsafe.Add(unsafe.Pointer(&port.PIN0CTRL), p%8)) - ctrlAddress.Set(pinctrl) - - // Configure the pin as input (if it wasn't an input pin before). - port.DIRCLR.Set(mask) - } -} - -// Get returns the current value of a GPIO pin when the pin is configured as an -// input or as an output. -func (p Pin) Get() bool { - port, mask := p.getPortMask() - // As noted above, the PINx register is always two registers below the PORTx - // register, so we can find it simply by subtracting two from the PORTx - // register address. - return (port.IN.Get() & mask) > 0 -} - -// Set changes the value of the GPIO pin. The pin must be configured as output. -func (p Pin) Set(high bool) { - port, mask := p.getPortMask() - if high { - port.OUTSET.Set(mask) - } else { - port.OUTCLR.Set(mask) - } -} diff --git a/emb/machine/machine_cortexm.go b/emb/machine/machine_cortexm.go deleted file mode 100644 index 0f8f264..0000000 --- a/emb/machine/machine_cortexm.go +++ /dev/null @@ -1,10 +0,0 @@ -//go:build cortexm - -package machine - -import "device/arm" - -// CPUReset performs a hard system reset. -func CPUReset() { - arm.SystemReset() -} diff --git a/emb/machine/machine_esp32.go b/emb/machine/machine_esp32.go deleted file mode 100644 index 237a129..0000000 --- a/emb/machine/machine_esp32.go +++ /dev/null @@ -1,545 +0,0 @@ -//go:build esp32 - -package machine - -import ( - "device/esp" - "errors" - "runtime/volatile" - "unsafe" -) - -const deviceName = esp.Device - -const peripheralClock = 80000000 // 80MHz - -// CPUFrequency returns the current CPU frequency of the chip. -// Currently it is a fixed frequency but it may allow changing in the future. -func CPUFrequency() uint32 { - return 160e6 // 160MHz -} - -var ( - ErrInvalidSPIBus = errors.New("machine: invalid SPI bus") -) - -const ( - PinOutput PinMode = iota - PinInput - PinInputPullup - PinInputPulldown -) - -// Hardware pin numbers -const ( - GPIO0 Pin = 0 - GPIO1 Pin = 1 - GPIO2 Pin = 2 - GPIO3 Pin = 3 - GPIO4 Pin = 4 - GPIO5 Pin = 5 - GPIO6 Pin = 6 - GPIO7 Pin = 7 - GPIO8 Pin = 8 - GPIO9 Pin = 9 - GPIO10 Pin = 10 - GPIO11 Pin = 11 - GPIO12 Pin = 12 - GPIO13 Pin = 13 - GPIO14 Pin = 14 - GPIO15 Pin = 15 - GPIO16 Pin = 16 - GPIO17 Pin = 17 - GPIO18 Pin = 18 - GPIO19 Pin = 19 - GPIO21 Pin = 21 - GPIO22 Pin = 22 - GPIO23 Pin = 23 - GPIO25 Pin = 25 - GPIO26 Pin = 26 - GPIO27 Pin = 27 - GPIO32 Pin = 32 - GPIO33 Pin = 33 - GPIO34 Pin = 34 - GPIO35 Pin = 35 - GPIO36 Pin = 36 - GPIO37 Pin = 37 - GPIO38 Pin = 38 - GPIO39 Pin = 39 -) - -// Configure this pin with the given configuration. -func (p Pin) Configure(config PinConfig) { - // Output function 256 is a special value reserved for use as a regular GPIO - // pin. Peripherals (SPI etc) can set a custom output function by calling - // lowercase configure() instead with a signal name. - p.configure(config, 256) -} - -// configure is the same as Configure, but allows for setting a specific input -// or output signal. -// Signals are always routed through the GPIO matrix for simplicity. Output -// signals are configured in FUNCx_OUT_SEL_CFG which selects a particular signal -// to output on a given pin. Input signals are configured in FUNCy_IN_SEL_CFG, -// which sets the pin to use for a particular input signal. -func (p Pin) configure(config PinConfig, signal uint32) { - if p == NoPin { - // This simplifies pin configuration in peripherals such as SPI. - return - } - - var muxConfig uint32 // The mux configuration. - - // Configure this pin as a GPIO pin. - const function = 3 // function 3 is GPIO for every pin - muxConfig |= (function - 1) << esp.IO_MUX_GPIO0_MCU_SEL_Pos - - // Make this pin an input pin (always). - muxConfig |= esp.IO_MUX_GPIO0_FUN_IE - - // Set drive strength: 0 is lowest, 3 is highest. - muxConfig |= 2 << esp.IO_MUX_GPIO0_FUN_DRV_Pos - - // Select pull mode. - if config.Mode == PinInputPullup { - muxConfig |= esp.IO_MUX_GPIO0_FUN_WPU - } else if config.Mode == PinInputPulldown { - muxConfig |= esp.IO_MUX_GPIO0_FUN_WPD - } - - // Configure the pad with the given IO mux configuration. - p.mux().Set(muxConfig) - - switch config.Mode { - case PinOutput: - // Set the 'output enable' bit. - if p < 32 { - esp.GPIO.ENABLE_W1TS.Set(1 << p) - } else { - esp.GPIO.ENABLE1_W1TS.Set(1 << (p - 32)) - } - // Set the signal to read the output value from. It can be a peripheral - // output signal, or the special value 256 which indicates regular GPIO - // usage. - p.outFunc().Set(signal) - case PinInput, PinInputPullup, PinInputPulldown: - // Clear the 'output enable' bit. - if p < 32 { - esp.GPIO.ENABLE_W1TC.Set(1 << p) - } else { - esp.GPIO.ENABLE1_W1TC.Set(1 << (p - 32)) - } - if signal != 256 { - // Signal is a peripheral function (not a simple GPIO). Connect this - // signal to the pin. - // Note that outFunc and inFunc work in the opposite direction. - // outFunc configures a pin to use a given output signal, while - // inFunc specifies a pin to use to read the signal from. - inFunc(signal).Set(esp.GPIO_FUNC_IN_SEL_CFG_SEL | uint32(p)< pad mapping. - // I couldn't find it. - switch p { - case 36: - return &esp.IO_MUX.GPIO36 - case 37: - return &esp.IO_MUX.GPIO37 - case 38: - return &esp.IO_MUX.GPIO38 - case 39: - return &esp.IO_MUX.GPIO39 - case 34: - return &esp.IO_MUX.GPIO34 - case 35: - return &esp.IO_MUX.GPIO35 - case 32: - return &esp.IO_MUX.GPIO32 - case 33: - return &esp.IO_MUX.GPIO33 - case 25: - return &esp.IO_MUX.GPIO25 - case 26: - return &esp.IO_MUX.GPIO26 - case 27: - return &esp.IO_MUX.GPIO27 - case 14: - return &esp.IO_MUX.GPIO14 - case 12: - return &esp.IO_MUX.GPIO12 - case 13: - return &esp.IO_MUX.GPIO13 - case 15: - return &esp.IO_MUX.GPIO15 - case 2: - return &esp.IO_MUX.GPIO2 - case 0: - return &esp.IO_MUX.GPIO0 - case 4: - return &esp.IO_MUX.GPIO4 - case 16: - return &esp.IO_MUX.GPIO16 - case 17: - return &esp.IO_MUX.GPIO17 - case 9: - return &esp.IO_MUX.GPIO9 - case 10: - return &esp.IO_MUX.GPIO10 - case 11: - return &esp.IO_MUX.GPIO11 - case 6: - return &esp.IO_MUX.GPIO6 - case 7: - return &esp.IO_MUX.GPIO7 - case 8: - return &esp.IO_MUX.GPIO8 - case 5: - return &esp.IO_MUX.GPIO5 - case 18: - return &esp.IO_MUX.GPIO18 - case 19: - return &esp.IO_MUX.GPIO19 - case 20: - return &esp.IO_MUX.GPIO20 - case 21: - return &esp.IO_MUX.GPIO21 - case 22: - return &esp.IO_MUX.GPIO22 - case 3: - return &esp.IO_MUX.GPIO3 - case 1: - return &esp.IO_MUX.GPIO1 - case 23: - return &esp.IO_MUX.GPIO23 - case 24: - return &esp.IO_MUX.GPIO24 - default: - return nil - } -} - -var DefaultUART = UART0 - -var ( - UART0 = &_UART0 - _UART0 = UART{Bus: esp.UART0, Buffer: NewRingBuffer()} - UART1 = &_UART1 - _UART1 = UART{Bus: esp.UART1, Buffer: NewRingBuffer()} - UART2 = &_UART2 - _UART2 = UART{Bus: esp.UART2, Buffer: NewRingBuffer()} -) - -type UART struct { - Bus *esp.UART_Type - Buffer *RingBuffer -} - -func (uart *UART) Configure(config UARTConfig) { - if config.BaudRate == 0 { - config.BaudRate = 115200 - } - uart.Bus.CLKDIV.Set(peripheralClock / config.BaudRate) -} - -func (uart *UART) writeByte(b byte) error { - for (uart.Bus.STATUS.Get()>>16)&0xff >= 128 { - // Read UART_TXFIFO_CNT from the status register, which indicates how - // many bytes there are in the transmit buffer. Wait until there are - // less than 128 bytes in this buffer (the default buffer size). - } - // Write to the TX_FIFO register. - (*volatile.Register8)(unsafe.Add(unsafe.Pointer(uart.Bus), 0x200C0000)).Set(b) - return nil -} - -func (uart *UART) flush() {} - -// Serial Peripheral Interface on the ESP32. -type SPI struct { - Bus *esp.SPI_Type -} - -var ( - // SPI0 and SPI1 are reserved for use by the caching system etc. - SPI2 = &SPI{esp.SPI2} - SPI3 = &SPI{esp.SPI3} -) - -// SPIConfig configures a SPI peripheral on the ESP32. Make sure to set at least -// SCK, SDO and SDI (possibly to NoPin if not in use). The default for LSBFirst -// (false) and Mode (0) are good for most applications. The frequency defaults -// to 1MHz if not set but can be configured up to 40MHz. Possible values are -// 40MHz and integer divisions from 40MHz such as 20MHz, 13.3MHz, 10MHz, 8MHz, -// etc. -type SPIConfig struct { - Frequency uint32 - SCK Pin - SDO Pin - SDI Pin - LSBFirst bool - Mode uint8 -} - -// Configure and make the SPI peripheral ready to use. -func (spi *SPI) Configure(config SPIConfig) error { - if config.Frequency == 0 { - config.Frequency = 4e6 // default to 4MHz - } - - // Configure the SPI clock. This assumes a peripheral clock of 80MHz. - var clockReg uint32 - if config.Frequency > 40e6 { - // Don't use a prescaler, but directly connect to the APB clock. This - // results in a SPI clock frequency of 40MHz. - clockReg |= esp.SPI_CLOCK_CLK_EQU_SYSCLK - } else { - // Use a prescaler for frequencies below 40MHz. They will get rounded - // down to the next possible frequency (20MHz, 13.3MHz, 10MHz, 8MHz, - // 6.7MHz, 5.7MHz, 5MHz, etc). - // This code is much simpler than how ESP-IDF configures the frequency, - // but should be just as accurate. The only exception is for frequencies - // below 4883Hz, which will need special support. - if config.Frequency < 4883 { - // The current lower limit is 4883Hz. - // The hardware supports lower frequencies by setting the h and n - // variables, but that's not yet implemented. - config.Frequency = 4883 - } - // The prescaler value is 40e6 / config.Frequency, but rounded up so - // that the actual frequency is never higher than the frequency - // requested in config.Frequency. - var ( - pre uint32 = (40e6 + config.Frequency - 1) / config.Frequency - n uint32 = 2 // this value seems to equal the number of ticks per SPI clock tick - h uint32 = 1 // must be half of n according to the formula in the reference manual - l uint32 = n // must equal n according to the reference manual - ) - clockReg |= (pre - 1) << esp.SPI_CLOCK_CLKDIV_PRE_Pos - clockReg |= (n - 1) << esp.SPI_CLOCK_CLKCNT_N_Pos - clockReg |= (h - 1) << esp.SPI_CLOCK_CLKCNT_H_Pos - clockReg |= (l - 1) << esp.SPI_CLOCK_CLKCNT_L_Pos - } - spi.Bus.CLOCK.Set(clockReg) - - // SPI_CTRL_REG controls bit order. - var ctrlReg uint32 - if config.LSBFirst { - ctrlReg |= esp.SPI_CTRL_WR_BIT_ORDER - ctrlReg |= esp.SPI_CTRL_RD_BIT_ORDER - } - spi.Bus.CTRL.Set(ctrlReg) - - // SPI_CTRL2_REG, SPI_USER_REG and SPI_PIN_REG control SPI clock polarity - // (mode), among others. - var ctrl2Reg, userReg, pinReg uint32 - // For mode configuration, see table 29 in the reference manual (page 128). - switch config.Mode { - case 0: - case 1: - userReg |= esp.SPI_USER_CK_OUT_EDGE - case 2: - userReg |= esp.SPI_USER_CK_OUT_EDGE - pinReg |= esp.SPI_PIN_CK_IDLE_EDGE - case 3: - pinReg |= esp.SPI_PIN_CK_IDLE_EDGE - } - // Enable full-duplex communication. - userReg |= esp.SPI_USER_DOUTDIN - userReg |= esp.SPI_USER_USR_MOSI - // Write values to registers. - spi.Bus.CTRL2.Set(ctrl2Reg) - spi.Bus.USER.Set(userReg) - spi.Bus.PIN.Set(pinReg) - - // Configure pins. - // TODO: use direct output if possible, if the configured pins match the - // possible direct configurations (e.g. for SPI2, when SCK is pin 14 etc). - if spi.Bus == esp.SPI2 { - config.SCK.configure(PinConfig{Mode: PinOutput}, 8) // HSPICLK - config.SDI.configure(PinConfig{Mode: PinInput}, 9) // HSPIQ - config.SDO.configure(PinConfig{Mode: PinOutput}, 10) // HSPID - } else if spi.Bus == esp.SPI3 { - config.SCK.configure(PinConfig{Mode: PinOutput}, 63) // VSPICLK - config.SDI.configure(PinConfig{Mode: PinInput}, 64) // VSPIQ - config.SDO.configure(PinConfig{Mode: PinOutput}, 65) // VSPID - } else { - // Don't know how to configure this bus. - return ErrInvalidSPIBus - } - - return nil -} - -// Transfer writes/reads a single byte using the SPI interface. If you need to -// transfer larger amounts of data, Tx will be faster. -func (spi *SPI) Transfer(w byte) (byte, error) { - spi.Bus.MISO_DLEN.Set(7 << esp.SPI_MISO_DLEN_USR_MISO_DBITLEN_Pos) - spi.Bus.MOSI_DLEN.Set(7 << esp.SPI_MOSI_DLEN_USR_MOSI_DBITLEN_Pos) - - spi.Bus.W0.Set(uint32(w)) - - // Send/receive byte. - spi.Bus.CMD.Set(esp.SPI_CMD_USR) - for spi.Bus.CMD.Get() != 0 { - } - - // The received byte is stored in W0. - return byte(spi.Bus.W0.Get()), nil -} - -// Tx handles read/write operation for SPI interface. Since SPI is a synchronous write/read -// interface, there must always be the same number of bytes written as bytes read. -// This is accomplished by sending zero bits if r is bigger than w or discarding -// the incoming data if w is bigger than r. -func (spi *SPI) Tx(w, r []byte) error { - toTransfer := len(w) - if len(r) > toTransfer { - toTransfer = len(r) - } - - for toTransfer != 0 { - // Do only 64 bytes at a time. - chunkSize := toTransfer - if chunkSize > 64 { - chunkSize = 64 - } - - // Fill tx buffer. - transferWords := (*[16]volatile.Register32)(unsafe.Pointer(uintptr(unsafe.Pointer(&spi.Bus.W0)))) - if len(w) >= 64 { - // We can fill the entire 64-byte transfer buffer with data. - // This loop is slightly faster than the loop below. - for i := 0; i < 16; i++ { - word := uint32(w[i*4])<<0 | uint32(w[i*4+1])<<8 | uint32(w[i*4+2])<<16 | uint32(w[i*4+3])<<24 - transferWords[i].Set(word) - } - } else { - // We can't fill the entire transfer buffer, so we need to be a bit - // more careful. - // Note that parts of the transfer buffer that aren't used still - // need to be set to zero, otherwise we might be transferring - // garbage from a previous transmission if w is smaller than r. - for i := 0; i < 16; i++ { - var word uint32 - if i*4+3 < len(w) { - word |= uint32(w[i*4+3]) << 24 - } - if i*4+2 < len(w) { - word |= uint32(w[i*4+2]) << 16 - } - if i*4+1 < len(w) { - word |= uint32(w[i*4+1]) << 8 - } - if i*4+0 < len(w) { - word |= uint32(w[i*4+0]) << 0 - } - transferWords[i].Set(word) - } - } - - // Do the transfer. - spi.Bus.MISO_DLEN.Set((uint32(chunkSize)*8 - 1) << esp.SPI_MISO_DLEN_USR_MISO_DBITLEN_Pos) - spi.Bus.MOSI_DLEN.Set((uint32(chunkSize)*8 - 1) << esp.SPI_MOSI_DLEN_USR_MOSI_DBITLEN_Pos) - spi.Bus.CMD.Set(esp.SPI_CMD_USR) - for spi.Bus.CMD.Get() != 0 { - } - - // Read rx buffer. - rxSize := 64 - if rxSize > len(r) { - rxSize = len(r) - } - for i := 0; i < rxSize; i++ { - r[i] = byte(transferWords[i/4].Get() >> ((i % 4) * 8)) - } - - // Cut off some part of the output buffer so the next iteration we will - // only send the remaining bytes. - if len(w) < chunkSize { - w = nil - } else { - w = w[chunkSize:] - } - if len(r) < chunkSize { - r = nil - } else { - r = r[chunkSize:] - } - toTransfer -= chunkSize - } - - return nil -} diff --git a/emb/machine/machine_esp32_i2c.go b/emb/machine/machine_esp32_i2c.go deleted file mode 100644 index 746e722..0000000 --- a/emb/machine/machine_esp32_i2c.go +++ /dev/null @@ -1,412 +0,0 @@ -//go:build esp32 - -package machine - -import ( - "device/esp" - "runtime/volatile" - "unsafe" -) - -var ( - I2C0 = &I2C{Bus: esp.I2C0, funcSCL: 29, funcSDA: 30} - I2C1 = &I2C{Bus: esp.I2C1, funcSCL: 95, funcSDA: 96} -) - -type I2C struct { - Bus *esp.I2C_Type - funcSCL, funcSDA uint32 - config I2CConfig -} - -// I2CConfig is used to store config info for I2C. -type I2CConfig struct { - Frequency uint32 // in Hz - SCL Pin - SDA Pin -} - -const ( - i2cClkSourceFrequency = uint32(80 * MHz) -) - -func (i2c *I2C) Configure(config I2CConfig) error { - if config.Frequency == 0 { - config.Frequency = 400 * KHz - } - if config.SCL == 0 { - config.SCL = SCL_PIN - } - if config.SDA == 0 { - config.SDA = SDA_PIN - } - i2c.config = config - - i2c.initAll() - return nil -} - -func (i2c *I2C) initAll() { - i2c.initClock() - i2c.initNoiseFilter() - i2c.initPins() - i2c.initFrequency() - i2c.startMaster() -} - -//go:inline -func (i2c *I2C) initClock() { - // reset I2C clock - if i2c.Bus == esp.I2C0 { - esp.DPORT.SetPERIP_RST_EN_I2C0_EXT0_RST(1) - esp.DPORT.SetPERIP_CLK_EN_I2C0_EXT0_CLK_EN(1) - esp.DPORT.SetPERIP_RST_EN_I2C0_EXT0_RST(0) - } else { - esp.DPORT.SetPERIP_RST_EN_I2C_EXT1_RST(1) - esp.DPORT.SetPERIP_CLK_EN_I2C_EXT1_CLK_EN(1) - esp.DPORT.SetPERIP_RST_EN_I2C_EXT1_RST(0) - } - // disable interrupts - i2c.Bus.INT_ENA.Set(0) - i2c.Bus.INT_CLR.Set(0x3fff) - - i2c.Bus.SetCTR_CLK_EN(1) -} - -//go:inline -func (i2c *I2C) initNoiseFilter() { - i2c.Bus.SCL_FILTER_CFG.Set(0xF) - i2c.Bus.SDA_FILTER_CFG.Set(0xF) -} - -//go:inline -func (i2c *I2C) initPins() { - var muxConfig uint32 - const function = 2 // function 2 is just GPIO - - // SDA - muxConfig = function << esp.IO_MUX_GPIO0_MCU_SEL_Pos - // Make this pin an input pin (always). - muxConfig |= esp.IO_MUX_GPIO0_FUN_IE - // Set drive strength: 0 is lowest, 3 is highest. - muxConfig |= 1 << esp.IO_MUX_GPIO0_FUN_DRV_Pos - i2c.config.SDA.mux().Set(muxConfig) - i2c.config.SDA.outFunc().Set(i2c.funcSDA) - inFunc(i2c.funcSDA).Set(uint32(esp.GPIO_FUNC_IN_SEL_CFG_SEL | i2c.config.SDA)) - i2c.config.SDA.Set(true) - // Configure the pad with the given IO mux configuration. - i2c.config.SDA.pinReg().SetBits(esp.GPIO_PIN_PAD_DRIVER) - - esp.GPIO.ENABLE_W1TS.Set(1 << int(i2c.config.SDA)) - i2c.Bus.SetCTR_SDA_FORCE_OUT(1) - - // SCL - muxConfig = function << esp.IO_MUX_GPIO0_MCU_SEL_Pos - // Make this pin an input pin (always). - muxConfig |= esp.IO_MUX_GPIO0_FUN_IE - // Set drive strength: 0 is lowest, 3 is highest. - muxConfig |= 1 << esp.IO_MUX_GPIO0_FUN_DRV_Pos - i2c.config.SCL.mux().Set(muxConfig) - i2c.config.SCL.outFunc().Set(i2c.funcSCL) - inFunc(i2c.funcSCL).Set(uint32(esp.GPIO_FUNC_IN_SEL_CFG_SEL | i2c.config.SCL)) - i2c.config.SCL.Set(true) - // Configure the pad with the given IO mux configuration. - i2c.config.SCL.pinReg().SetBits(esp.GPIO_PIN_PAD_DRIVER) - - esp.GPIO.ENABLE_W1TS.Set(1 << int(i2c.config.SCL)) - i2c.Bus.SetCTR_SCL_FORCE_OUT(1) -} - -//go:inline -func (i2c *I2C) initFrequency() { - clkmDiv := i2cClkSourceFrequency/(i2c.config.Frequency*1024) + 1 - sclkFreq := i2cClkSourceFrequency / clkmDiv - halfCycle := sclkFreq / i2c.config.Frequency / 2 - //SCL - sclLow := halfCycle - sclWaitHigh := uint32(0) - if i2c.config.Frequency > 50000 { - sclWaitHigh = halfCycle / 8 // compensate the time when freq > 50K - } - sclHigh := halfCycle - sclWaitHigh - // SDA - sdaHold := halfCycle / 4 - sda_sample := halfCycle / 2 - setup := halfCycle - hold := halfCycle - - i2c.Bus.SetSCL_LOW_PERIOD(sclLow - 1) - i2c.Bus.SetSCL_HIGH_PERIOD(sclHigh) - i2c.Bus.SetSCL_RSTART_SETUP_TIME(setup) - i2c.Bus.SetSCL_STOP_SETUP_TIME(setup) - i2c.Bus.SetSCL_START_HOLD_TIME(hold - 1) - i2c.Bus.SetSCL_STOP_HOLD_TIME(hold - 1) - i2c.Bus.SetSDA_SAMPLE_TIME(sda_sample) - i2c.Bus.SetSDA_HOLD_TIME(sdaHold) - // set timeout value - i2c.Bus.SetTO_TIME_OUT(20 * halfCycle) -} - -//go:inline -func (i2c *I2C) startMaster() { - // FIFO mode for data - i2c.Bus.SetFIFO_CONF_NONFIFO_EN(0) - // Reset TX & RX buffers - i2c.Bus.SetFIFO_CONF_RX_FIFO_RST(1) - i2c.Bus.SetFIFO_CONF_RX_FIFO_RST(0) - i2c.Bus.SetFIFO_CONF_TX_FIFO_RST(1) - i2c.Bus.SetFIFO_CONF_TX_FIFO_RST(0) - // enable master mode - i2c.Bus.SetCTR_MS_MODE(1) -} - -func (i2c *I2C) resetBus() { - // unlike esp32c3, the esp32 i2c modules do not have a reset fsm register, - // so we need to: - // 1. disconnect the pins - // 2. generate a stop condition manually - // 3. do a full reset - // 4. redo all configuration - - i2c.config.SDA.mux().Set(2< 0 && c.head < len(c.data); count, c.head = count-1, c.head+1 { - i2c.Bus.SetDATA_FIFO_RDATA(uint32(c.data[c.head])) - } - reg.Set(i2cCMD_WRITE | uint32(32-count)) - reg = nextAddress(reg) - - if c.head < len(c.data) { - reg.Set(i2cCMD_END) - reg = nil - } else { - cmdIdx++ - } - needRestart = true - - case i2cCMD_READ: - if needAddress { - needAddress = false - i2c.Bus.SetDATA_FIFO_RDATA((uint32(addr)&0x7f)<<1 | 1) - i2c.Bus.SLAVE_ADDR.Set(uint32(addr)) - reg.Set(i2cCMD_WRITE | 1) - reg = nextAddress(reg) - } - if needRestart { - // We need to send RESTART again after i2cCMD_WRITE. - reg.Set(i2cCMD_RSTART) - - reg = nextAddress(reg) - reg.Set(i2cCMD_WRITE | 1) - - reg = nextAddress(reg) - i2c.Bus.SetDATA_FIFO_RDATA((uint32(addr)&0x7f)<<1 | 1) - needRestart = false - } - count := 32 - bytes := len(c.data) - c.head - // Only last byte in sequence must be sent with ACK set to 1 to indicate end of data. - split := bytes <= count - if split { - bytes-- - } - if bytes > 32 { - bytes = 32 - } - if bytes > 0 { - reg.Set(i2cCMD_READ | uint32(bytes)) - reg = nextAddress(reg) - } - - if split { - readLast = true - reg.Set(i2cCMD_READLAST | 1) - reg = nextAddress(reg) - readTo = c.data[c.head : c.head+bytes+1] // read bytes + 1 last byte - cmdIdx++ - } else { - reg.Set(i2cCMD_END) - readTo = c.data[c.head : c.head+bytes] - reg = nil - } - - case i2cCMD_STOP: - reg.Set(i2cCMD_STOP) - reg = nil - cmdIdx++ - } - if reg == nil { - // transmit now - i2c.Bus.SetCTR_TRANS_START(1) - end := nanotime() + timeoutNS - var mask uint32 - for mask = i2c.Bus.INT_STATUS.Get(); mask&intMask == 0; mask = i2c.Bus.INT_STATUS.Get() { - if nanotime() > end { - // timeout leaves the bus in an undefined state, reset - i2c.resetBus() - if readTo != nil { - return errI2CReadTimeout - } - return errI2CWriteTimeout - } - } - switch { - case mask&esp.I2C_INT_STATUS_ACK_ERR_INT_ST_Msk != 0 && !readLast: - return errI2CAckExpected - case mask&esp.I2C_INT_STATUS_TIME_OUT_INT_ST_Msk != 0: - // timeout leaves the bus in an undefined state, reset - i2c.resetBus() - if readTo != nil { - return errI2CReadTimeout - } - return errI2CWriteTimeout - } - i2c.Bus.INT_CLR.SetBits(intMask) - for i := 0; i < len(readTo); i++ { - readTo[i] = byte(i2c.Bus.GetDATA_FIFO_RDATA() & 0xff) - c.head++ - } - readTo = nil - reg = &i2c.Bus.COMD0 - } - } - 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) (err error) { - // timeout in microseconds. - const timeout = 40 // 40ms is a reasonable time for a real-time system. - - cmd := make([]i2cCommand, 0, 8) - cmd = append(cmd, i2cCommand{cmd: i2cCMD_RSTART}) - if len(w) > 0 { - cmd = append(cmd, i2cCommand{cmd: i2cCMD_WRITE, data: w}) - } - if len(r) > 0 { - cmd = append(cmd, i2cCommand{cmd: i2cCMD_READ, data: r}) - } - cmd = append(cmd, i2cCommand{cmd: i2cCMD_STOP}) - - return i2c.transmit(addr, cmd, timeout) -} - -func (i2c *I2C) SetBaudRate(br uint32) error { - return errI2CNotImplemented -} - -func (p Pin) pinReg() *volatile.Register32 { - return (*volatile.Register32)(unsafe.Pointer((uintptr(unsafe.Pointer(&esp.GPIO.PIN0)) + uintptr(p)*4))) -} - -func nextAddress(reg *volatile.Register32) *volatile.Register32 { - return (*volatile.Register32)(unsafe.Add(unsafe.Pointer(reg), 4)) -} - -// CheckDevice does an empty I2C transaction at the specified address. -// This can be used to find out if any device with that address is -// connected, e.g. for enumerating all devices on the bus. -func (i2c *I2C) CheckDevice(addr uint16) bool { - // timeout in microseconds. - const timeout = 40 // 40ms is a reasonable time for a real-time system. - - cmd := []i2cCommand{ - {cmd: i2cCMD_RSTART}, - {cmd: i2cCMD_WRITE}, - {cmd: i2cCMD_STOP}, - } - return i2c.transmit(addr, cmd, timeout) == nil -} diff --git a/emb/machine/machine_esp32c3.go b/emb/machine/machine_esp32c3.go deleted file mode 100644 index 727fcc1..0000000 --- a/emb/machine/machine_esp32c3.go +++ /dev/null @@ -1,637 +0,0 @@ -//go:build esp32c3 - -package machine - -import ( - "device/esp" - "device/riscv" - "errors" - "runtime/interrupt" - "runtime/volatile" - "sync" - "unsafe" -) - -const deviceName = esp.Device -const maxPin = 22 -const cpuInterruptFromPin = 6 - -// CPUFrequency returns the current CPU frequency of the chip. -// Currently it is a fixed frequency but it may allow changing in the future. -func CPUFrequency() uint32 { - return 160e6 // 160MHz -} - -const ( - PinOutput PinMode = iota - PinInput - PinInputPullup - PinInputPulldown -) - -const ( - GPIO0 Pin = 0 - GPIO1 Pin = 1 - GPIO2 Pin = 2 - GPIO3 Pin = 3 - GPIO4 Pin = 4 - GPIO5 Pin = 5 - GPIO6 Pin = 6 - GPIO7 Pin = 7 - GPIO8 Pin = 8 - GPIO9 Pin = 9 - GPIO10 Pin = 10 - GPIO11 Pin = 11 - GPIO12 Pin = 12 - GPIO13 Pin = 13 - GPIO14 Pin = 14 - GPIO15 Pin = 15 - GPIO16 Pin = 16 - GPIO17 Pin = 17 - GPIO18 Pin = 18 - GPIO19 Pin = 19 - GPIO20 Pin = 20 - GPIO21 Pin = 21 -) - -type PinChange uint8 - -// Pin change interrupt constants for SetInterrupt. -const ( - PinRising PinChange = iota + 1 - PinFalling - PinToggle -) - -// Configure this pin with the given configuration. -func (p Pin) Configure(config PinConfig) { - if p == NoPin { - // This simplifies pin configuration in peripherals such as SPI. - return - } - - var muxConfig uint32 - - // Configure this pin as a GPIO pin. - const function = 1 // function 1 is GPIO for every pin - muxConfig |= function << esp.IO_MUX_GPIO_MCU_SEL_Pos - - // Make this pin an input pin (always). - muxConfig |= esp.IO_MUX_GPIO_FUN_IE - - // Set drive strength: 0 is lowest, 3 is highest. - muxConfig |= 2 << esp.IO_MUX_GPIO_FUN_DRV_Pos - - // Select pull mode. - if config.Mode == PinInputPullup { - muxConfig |= esp.IO_MUX_GPIO_FUN_WPU - } else if config.Mode == PinInputPulldown { - muxConfig |= esp.IO_MUX_GPIO_FUN_WPD - } - - // Configure the pad with the given IO mux configuration. - p.mux().Set(muxConfig) - - // Set the output signal to the simple GPIO output. - p.outFunc().Set(0x80) - - switch config.Mode { - case PinOutput: - // Set the 'output enable' bit. - esp.GPIO.ENABLE_W1TS.Set(1 << p) - case PinInput, PinInputPullup, PinInputPulldown: - // Clear the 'output enable' bit. - esp.GPIO.ENABLE_W1TC.Set(1 << p) - } -} - -// outFunc returns the FUNCx_OUT_SEL_CFG register used for configuring the -// output function selection. -func (p Pin) outFunc() *volatile.Register32 { - return (*volatile.Register32)(unsafe.Add(unsafe.Pointer(&esp.GPIO.FUNC0_OUT_SEL_CFG), uintptr(p)*4)) -} - -func (p Pin) pinReg() *volatile.Register32 { - return (*volatile.Register32)(unsafe.Pointer((uintptr(unsafe.Pointer(&esp.GPIO.PIN0)) + uintptr(p)*4))) -} - -// inFunc returns the FUNCy_IN_SEL_CFG register used for configuring the input -// function selection. -func inFunc(signal uint32) *volatile.Register32 { - return (*volatile.Register32)(unsafe.Add(unsafe.Pointer(&esp.GPIO.FUNC0_IN_SEL_CFG), uintptr(signal)*4)) -} - -// mux returns the I/O mux configuration register corresponding to the given -// GPIO pin. -func (p Pin) mux() *volatile.Register32 { - return (*volatile.Register32)(unsafe.Add(unsafe.Pointer(&esp.IO_MUX.GPIO0), uintptr(p)*4)) -} - -// pin returns the PIN register corresponding to the given GPIO pin. -func (p Pin) pin() *volatile.Register32 { - return (*volatile.Register32)(unsafe.Add(unsafe.Pointer(&esp.GPIO.PIN0), uintptr(p)*4)) -} - -// Set the pin to high or low. -// Warning: only use this on an output pin! -func (p Pin) Set(value bool) { - if value { - reg, mask := p.portMaskSet() - reg.Set(mask) - } else { - reg, mask := p.portMaskClear() - reg.Set(mask) - } -} - -// Get returns the current value of a GPIO pin when configured as an input or as -// an output. -func (p Pin) Get() bool { - reg := &esp.GPIO.IN - return (reg.Get()>>p)&1 > 0 -} - -// Return the register and mask to enable a given GPIO pin. This can be used to -// implement bit-banged drivers. -// -// Warning: only use this on an output pin! -func (p Pin) PortMaskSet() (*uint32, uint32) { - reg, mask := p.portMaskSet() - return ®.Reg, mask -} - -// Return the register and mask to disable a given GPIO pin. This can be used to -// implement bit-banged drivers. -// -// Warning: only use this on an output pin! -func (p Pin) PortMaskClear() (*uint32, uint32) { - reg, mask := p.portMaskClear() - return ®.Reg, mask -} - -func (p Pin) portMaskSet() (*volatile.Register32, uint32) { - return &esp.GPIO.OUT_W1TS, 1 << p -} - -func (p Pin) portMaskClear() (*volatile.Register32, uint32) { - return &esp.GPIO.OUT_W1TC, 1 << p -} - -// SetInterrupt sets an interrupt to be executed when a particular pin changes -// state. The pin should already be configured as an input, including a pull up -// or down if no external pull is provided. -// -// You can pass a nil func to unset the pin change interrupt. If you do so, -// the change parameter is ignored and can be set to any value (such as 0). -// If the pin is already configured with a callback, you must first unset -// this pins interrupt before you can set a new callback. -func (p Pin) SetInterrupt(change PinChange, callback func(Pin)) (err error) { - if p >= maxPin { - return ErrInvalidInputPin - } - - if callback == nil { - // Disable this pin interrupt - p.pin().ClearBits(esp.GPIO_PIN_INT_TYPE_Msk | esp.GPIO_PIN_INT_ENA_Msk) - - if pinCallbacks[p] != nil { - pinCallbacks[p] = nil - } - return nil - } - - if pinCallbacks[p] != nil { - // The pin was already configured. - // To properly re-configure a pin, unset it first and set a new - // configuration. - return ErrNoPinChangeChannel - } - pinCallbacks[p] = callback - - onceSetupPinInterrupt.Do(func() { - err = setupPinInterrupt() - }) - if err != nil { - return err - } - - p.pin().Set( - (p.pin().Get() & ^uint32(esp.GPIO_PIN_INT_TYPE_Msk|esp.GPIO_PIN_INT_ENA_Msk)) | - uint32(change)< 1 { - return errWrongStopBitSize - } - // - data length - uart.Bus.SetCONF0_BIT_NUM(uint32(dataBits - 5)) - // - stop bit - uart.Bus.SetCONF0_STOP_BIT_NUM(uint32(stopBits)) - // - parity check - switch parity { - case ParityNone: - uart.Bus.SetCONF0_PARITY_EN(0) - case ParityEven: - uart.Bus.SetCONF0_PARITY_EN(1) - uart.Bus.SetCONF0_PARITY(0) - case ParityOdd: - uart.Bus.SetCONF0_PARITY_EN(1) - uart.Bus.SetCONF0_PARITY(1) - } - return nil -} - -func initUARTClock(bus *esp.UART_Type, regs registerSet) { - uartClock := &esp.SYSTEM.PERIP_CLK_EN0 - uartClockReset := &esp.SYSTEM.PERIP_RST_EN0 - - // Initialize/reset URATn (Ref: Initializing URATn) - // - enable the clock for UART RAM - uartClock.SetBits(esp.SYSTEM_PERIP_CLK_EN0_UART_MEM_CLK_EN) - // - enable APB_CLK for UARTn - uartClock.SetBits(regs.uartClockBitMask) - // - reset sequence - uartClockReset.ClearBits(regs.uartClockBitMask) - bus.SetCLK_CONF_RST_CORE(1) - uartClockReset.SetBits(regs.uartClockBitMask) - uartClockReset.ClearBits(regs.uartClockBitMask) - bus.SetCLK_CONF_RST_CORE(0) - // synchronize core register - bus.SetID_REG_UPDATE(0) - // enable RTC clock - esp.RTC_CNTL.SetCLK_CONF_DIG_CLK8M_EN(1) - // wait for Core Clock to ready for configuration - for bus.GetID_REG_UPDATE() > 0 { - riscv.Asm("nop") - } -} - -func (uart *UART) SetBaudRate(baudRate uint32) { - // based on esp-idf - max_div := uint32((1 << 12) - 1) - sclk_div := (pplClockFreq + (max_div * baudRate) - 1) / (max_div * baudRate) - clk_div := (pplClockFreq << 4) / (baudRate * sclk_div) - uart.Bus.SetCLKDIV(clk_div >> 4) - uart.Bus.SetCLKDIV_FRAG(clk_div & 0xf) - uart.Bus.SetCLK_CONF_SCLK_DIV_NUM(sclk_div - 1) -} - -func (uart *UART) setupPins(config UARTConfig, regs registerSet) { - config.RX.Configure(PinConfig{Mode: PinInputPullup}) - config.TX.Configure(PinConfig{Mode: PinInputPullup}) - - // link TX with GPIO signal X (technical reference manual 5.10) (this is not interrupt signal!) - config.TX.outFunc().Set(regs.gpioMatrixSignal) - // link RX with GPIO signal X and route signals via GPIO matrix (GPIO_SIGn_IN_SEL 0x40) - inFunc(regs.gpioMatrixSignal).Set(esp.GPIO_FUNC_IN_SEL_CFG_SEL | uint32(config.RX)) -} - -func (uart *UART) configureInterrupt(intrMapReg *volatile.Register32) { // Disable all UART interrupts - // Disable all UART interrupts - uart.Bus.INT_ENA.ClearBits(0x0ffff) - - intrMapReg.Set(7) - onceUart.Do(func() { - _ = interrupt.New(7, func(i interrupt.Interrupt) { - UART0.serveInterrupt(0) - UART1.serveInterrupt(1) - }).Enable() - }) -} - -func (uart *UART) serveInterrupt(num int) { - // get interrupt status - interrutFlag := uart.Bus.INT_ST.Get() - if (interrutFlag & uartInterrupts) == 0 { - return - } - - // block UART interrupts while processing - uart.Bus.INT_ENA.ClearBits(uartInterrupts) - - if interrutFlag&esp.UART_INT_ENA_RXFIFO_FULL_INT_ENA > 0 { - for uart.Bus.GetSTATUS_RXFIFO_CNT() > 0 { - b := uart.Bus.GetFIFO_RXFIFO_RD_BYTE() - if !uart.Buffer.Put(byte(b & 0xff)) { - uart.DataOverflowDetected = true - } - } - } - if interrutFlag&esp.UART_INT_ENA_PARITY_ERR_INT_ENA > 0 { - uart.ParityErrorDetected = true - } - if 0 != interrutFlag&esp.UART_INT_ENA_FRM_ERR_INT_ENA { - uart.DataErrorDetected = true - } - if 0 != interrutFlag&esp.UART_INT_ENA_RXFIFO_OVF_INT_ENA { - uart.DataOverflowDetected = true - } - if 0 != interrutFlag&esp.UART_INT_ENA_GLITCH_DET_INT_ENA { - uart.DataErrorDetected = true - } - - // Clear the UART interrupt status - uart.Bus.INT_CLR.SetBits(interrutFlag) - uart.Bus.INT_CLR.ClearBits(interrutFlag) - // Enable interrupts - uart.Bus.INT_ENA.Set(uartInterrupts) -} - -const uart_empty_thresh_default = 10 - -func (uart *UART) enableTransmitter() { - uart.Bus.SetCONF0_TXFIFO_RST(1) - uart.Bus.SetCONF0_TXFIFO_RST(0) - // TXINFO empty threshold is when txfifo_empty_int interrupt produced after the amount of data in Tx-FIFO is less than this register value. - uart.Bus.SetCONF1_TXFIFO_EMPTY_THRHD(uart_empty_thresh_default) - // we are not using interrupt on TX since write we are waiting for FIFO to have space. - // uart.Bus.INT_ENA.SetBits(esp.UART_INT_ENA_TXFIFO_EMPTY_INT_ENA) -} - -func (uart *UART) enableReceiver() { - uart.Bus.SetCONF0_RXFIFO_RST(1) - uart.Bus.SetCONF0_RXFIFO_RST(0) - // using value 1 so that we can start populate ring buffer with data as we get it - uart.Bus.SetCONF1_RXFIFO_FULL_THRHD(1) - // enable interrupts for: - uart.Bus.SetINT_ENA_RXFIFO_FULL_INT_ENA(1) - uart.Bus.SetINT_ENA_FRM_ERR_INT_ENA(1) - uart.Bus.SetINT_ENA_PARITY_ERR_INT_ENA(1) - uart.Bus.SetINT_ENA_GLITCH_DET_INT_ENA(1) - uart.Bus.SetINT_ENA_RXFIFO_OVF_INT_ENA(1) -} - -func (uart *UART) writeByte(b byte) error { - for (uart.Bus.STATUS.Get()&esp.UART_STATUS_TXFIFO_CNT_Msk)>>esp.UART_STATUS_TXFIFO_CNT_Pos >= 128 { - // Read UART_TXFIFO_CNT from the status register, which indicates how - // many bytes there are in the transmit buffer. Wait until there are - // less than 128 bytes in this buffer (the default buffer size). - } - uart.Bus.FIFO.Set(uint32(b)) - return nil -} - -func (uart *UART) flush() {} - -type Serialer interface { - WriteByte(c byte) error - Write(data []byte) (n int, err error) - Configure(config UARTConfig) error - Buffered() int - ReadByte() (byte, error) - DTR() bool - RTS() bool -} - -// USB Serial/JTAG Controller -// See esp32-c3_technical_reference_manual_en.pdf -// pg. 736 -type USB_DEVICE struct { - Bus *esp.USB_DEVICE_Type -} - -var ( - _USBCDC = &USB_DEVICE{ - Bus: esp.USB_DEVICE, - } - - USBCDC Serialer = _USBCDC -) - -var ( - errUSBWrongSize = errors.New("USB: invalid write size") - errUSBCouldNotWriteAllData = errors.New("USB: could not write all data") - errUSBBufferEmpty = errors.New("USB: read buffer empty") -) - -func (usbdev *USB_DEVICE) Configure(config UARTConfig) error { - return nil -} - -func (usbdev *USB_DEVICE) WriteByte(c byte) error { - if usbdev.Bus.GetEP1_CONF_SERIAL_IN_EP_DATA_FREE() == 0 { - return errUSBCouldNotWriteAllData - } - - usbdev.Bus.SetEP1_RDWR_BYTE(uint32(c)) - usbdev.flush() - - return nil -} - -func (usbdev *USB_DEVICE) Write(data []byte) (n int, err error) { - if len(data) == 0 || len(data) > 64 { - return 0, errUSBWrongSize - } - - for i, c := range data { - if usbdev.Bus.GetEP1_CONF_SERIAL_IN_EP_DATA_FREE() == 0 { - if i > 0 { - usbdev.flush() - } - - return i, errUSBCouldNotWriteAllData - } - usbdev.Bus.SetEP1_RDWR_BYTE(uint32(c)) - } - - usbdev.flush() - return len(data), nil -} - -func (usbdev *USB_DEVICE) Buffered() int { - return int(usbdev.Bus.GetEP1_CONF_SERIAL_OUT_EP_DATA_AVAIL()) -} - -func (usbdev *USB_DEVICE) ReadByte() (byte, error) { - if usbdev.Bus.GetEP1_CONF_SERIAL_OUT_EP_DATA_AVAIL() != 0 { - return byte(usbdev.Bus.GetEP1_RDWR_BYTE()), nil - } - - return 0, nil -} - -func (usbdev *USB_DEVICE) DTR() bool { - return false -} - -func (usbdev *USB_DEVICE) RTS() bool { - return false -} - -func (usbdev *USB_DEVICE) flush() { - usbdev.Bus.SetEP1_CONF_WR_DONE(1) - for usbdev.Bus.GetEP1_CONF_SERIAL_IN_EP_DATA_FREE() == 0 { - } -} - -// GetRNG returns 32-bit random numbers using the ESP32-C3 true random number generator, -// Random numbers are generated based on the thermal noise in the system and the -// asynchronous clock mismatch. -// For maximum entropy also make sure that the SAR_ADC is enabled. -// See esp32-c3_technical_reference_manual_en.pdf p.524 -func GetRNG() (ret uint32, err error) { - // ensure ADC clock is initialized - initADCClock() - - // ensure fast RTC clock is enabled - if esp.RTC_CNTL.GetCLK_CONF_DIG_CLK8M_EN() == 0 { - esp.RTC_CNTL.SetCLK_CONF_DIG_CLK8M_EN(1) - } - - return esp.APB_CTRL.GetRND_DATA(), nil -} - -func initADCClock() { - if esp.APB_SARADC.GetCLKM_CONF_CLK_EN() == 1 { - return - } - - // only support ADC_CTRL_CLK set to 1 - esp.APB_SARADC.SetCLKM_CONF_CLK_SEL(1) - - esp.APB_SARADC.SetCTRL_SARADC_SAR_CLK_GATED(1) - - esp.APB_SARADC.SetCLKM_CONF_CLKM_DIV_NUM(15) - esp.APB_SARADC.SetCLKM_CONF_CLKM_DIV_B(1) - esp.APB_SARADC.SetCLKM_CONF_CLKM_DIV_A(0) - - esp.APB_SARADC.SetCTRL_SARADC_SAR_CLK_DIV(1) - esp.APB_SARADC.SetCLKM_CONF_CLK_EN(1) -} diff --git a/emb/machine/machine_esp32c3_i2c.go b/emb/machine/machine_esp32c3_i2c.go deleted file mode 100644 index dd334b0..0000000 --- a/emb/machine/machine_esp32c3_i2c.go +++ /dev/null @@ -1,353 +0,0 @@ -//go:build esp32c3 && !m5stamp_c3 - -package machine - -import ( - "device/esp" - "runtime/volatile" - "unsafe" -) - -var ( - I2C0 = &I2C{} -) - -type I2C struct{} - -// I2CConfig is used to store config info for I2C. -type I2CConfig struct { - Frequency uint32 // in Hz - SCL Pin - SDA Pin -} - -const ( - clkXTAL = 0 - clkFOSC = 1 - clkXTALFrequency = uint32(40e6) - clkFOSCFrequency = uint32(17.5e6) - i2cClkSourceFrequency = clkXTALFrequency - i2cClkSource = clkXTAL -) - -func (i2c *I2C) Configure(config I2CConfig) error { - if config.Frequency == 0 { - config.Frequency = 400 * KHz - } - if config.SCL == 0 { - config.SCL = SCL_PIN - } - if config.SDA == 0 { - config.SDA = SDA_PIN - } - - i2c.initClock(config) - i2c.initNoiseFilter() - i2c.initPins(config) - i2c.initFrequency(config) - i2c.startMaster() - return nil -} - -//go:inline -func (i2c *I2C) initClock(config I2CConfig) { - // reset I2C clock - esp.SYSTEM.SetPERIP_RST_EN0_I2C_EXT0_RST(1) - esp.SYSTEM.SetPERIP_CLK_EN0_I2C_EXT0_CLK_EN(1) - esp.SYSTEM.SetPERIP_RST_EN0_I2C_EXT0_RST(0) - // disable interrupts - esp.I2C0.INT_ENA.ClearBits(0x3fff) - esp.I2C0.INT_CLR.ClearBits(0x3fff) - - esp.I2C0.SetCLK_CONF_SCLK_SEL(i2cClkSource) - esp.I2C0.SetCLK_CONF_SCLK_ACTIVE(1) - esp.I2C0.SetCLK_CONF_SCLK_DIV_NUM(i2cClkSourceFrequency / (config.Frequency * 1024)) - esp.I2C0.SetCTR_CLK_EN(1) -} - -//go:inline -func (i2c *I2C) initNoiseFilter() { - esp.I2C0.FILTER_CFG.Set(0x377) -} - -//go:inline -func (i2c *I2C) initPins(config I2CConfig) { - var muxConfig uint32 - const function = 1 // function 1 is just GPIO - - // SDA - muxConfig = function << esp.IO_MUX_GPIO_MCU_SEL_Pos - // Make this pin an input pin (always). - muxConfig |= esp.IO_MUX_GPIO_FUN_IE - // Set drive strength: 0 is lowest, 3 is highest. - muxConfig |= 1 << esp.IO_MUX_GPIO_FUN_DRV_Pos - config.SDA.mux().Set(muxConfig) - config.SDA.outFunc().Set(54) - inFunc(54).Set(uint32(esp.GPIO_FUNC_IN_SEL_CFG_SEL | config.SDA)) - config.SDA.Set(true) - // Configure the pad with the given IO mux configuration. - config.SDA.pinReg().SetBits(esp.GPIO_PIN_PAD_DRIVER) - - esp.GPIO.ENABLE.SetBits(1 << int(config.SDA)) - esp.I2C0.SetCTR_SDA_FORCE_OUT(1) - - // SCL - muxConfig = function << esp.IO_MUX_GPIO_MCU_SEL_Pos - // Make this pin an input pin (always). - muxConfig |= esp.IO_MUX_GPIO_FUN_IE - // Set drive strength: 0 is lowest, 3 is highest. - muxConfig |= 1 << esp.IO_MUX_GPIO_FUN_DRV_Pos - config.SCL.mux().Set(muxConfig) - config.SCL.outFunc().Set(53) - inFunc(53).Set(uint32(config.SCL)) - config.SCL.Set(true) - // Configure the pad with the given IO mux configuration. - config.SCL.pinReg().SetBits(esp.GPIO_PIN_PAD_DRIVER) - - esp.GPIO.ENABLE.SetBits(1 << int(config.SCL)) - esp.I2C0.SetCTR_SCL_FORCE_OUT(1) -} - -//go:inline -func (i2c *I2C) initFrequency(config I2CConfig) { - - clkmDiv := i2cClkSourceFrequency/(config.Frequency*1024) + 1 - sclkFreq := i2cClkSourceFrequency / clkmDiv - halfCycle := sclkFreq / config.Frequency / 2 - //SCL - sclLow := halfCycle - sclWaitHigh := uint32(0) - if config.Frequency > 50000 { - sclWaitHigh = halfCycle / 8 // compensate the time when freq > 50K - } - sclHigh := halfCycle - sclWaitHigh - // SDA - sdaHold := halfCycle / 4 - sda_sample := halfCycle / 2 - setup := halfCycle - hold := halfCycle - - esp.I2C0.SetSCL_LOW_PERIOD(sclLow - 1) - esp.I2C0.SetSCL_HIGH_PERIOD(sclHigh) - esp.I2C0.SetSCL_HIGH_PERIOD_SCL_WAIT_HIGH_PERIOD(25) - esp.I2C0.SetSCL_RSTART_SETUP_TIME(setup) - esp.I2C0.SetSCL_STOP_SETUP_TIME(setup) - esp.I2C0.SetSCL_START_HOLD_TIME(hold - 1) - esp.I2C0.SetSCL_STOP_HOLD_TIME(hold - 1) - esp.I2C0.SetSDA_SAMPLE_TIME(sda_sample) - esp.I2C0.SetSDA_HOLD_TIME(sdaHold) -} - -//go:inline -func (i2c *I2C) startMaster() { - // FIFO mode for data - esp.I2C0.SetFIFO_CONF_NONFIFO_EN(0) - // Reset TX & RX buffers - esp.I2C0.SetFIFO_CONF_RX_FIFO_RST(1) - esp.I2C0.SetFIFO_CONF_RX_FIFO_RST(0) - esp.I2C0.SetFIFO_CONF_TX_FIFO_RST(1) - esp.I2C0.SetFIFO_CONF_TX_FIFO_RST(0) - // set timeout value - esp.I2C0.TO.Set(0x10) - // enable master mode - esp.I2C0.CTR.Set(0x113) - esp.I2C0.SetCTR_CONF_UPGATE(1) - resetMaster() -} - -//go:inline -func resetMaster() { - // reset FSM - esp.I2C0.SetCTR_FSM_RST(1) - // clear the bus - esp.I2C0.SetSCL_SP_CONF_SCL_RST_SLV_NUM(9) - esp.I2C0.SetSCL_SP_CONF_SCL_RST_SLV_EN(1) - esp.I2C0.SetSCL_STRETCH_CONF_SLAVE_SCL_STRETCH_EN(1) - esp.I2C0.SetCTR_CONF_UPGATE(1) - esp.I2C0.FILTER_CFG.Set(0x377) - // wait for SCL_RST_SLV_EN - for esp.I2C0.GetSCL_SP_CONF_SCL_RST_SLV_EN() != 0 { - } - esp.I2C0.SetSCL_SP_CONF_SCL_RST_SLV_NUM(0) -} - -type i2cCommandType = uint32 -type i2cAck = uint32 - -const ( - i2cCMD_RSTART i2cCommandType = 6 << 11 - i2cCMD_WRITE i2cCommandType = 1<<11 | 1<<8 // WRITE + ack_check_en - i2cCMD_READ i2cCommandType = 3<<11 | 1<<8 // READ + ack_check_en - i2cCMD_READLAST i2cCommandType = 3<<11 | 5<<8 // READ + ack_check_en + NACK - i2cCMD_STOP i2cCommandType = 2 << 11 - i2cCMD_END i2cCommandType = 4 << 11 -) - -type i2cCommand struct { - cmd i2cCommandType - data []byte - head int -} - -//go:linkname nanotime runtime.nanotime -func nanotime() int64 - -func (i2c *I2C) transmit(addr uint16, cmd []i2cCommand, timeoutMS int) error { - const intMask = esp.I2C_INT_STATUS_END_DETECT_INT_ST_Msk | esp.I2C_INT_STATUS_TRANS_COMPLETE_INT_ST_Msk | esp.I2C_INT_STATUS_TIME_OUT_INT_ST_Msk | esp.I2C_INT_STATUS_NACK_INT_ST_Msk - esp.I2C0.INT_CLR.SetBits(intMask) - esp.I2C0.INT_ENA.SetBits(intMask) - esp.I2C0.SetCTR_CONF_UPGATE(1) - - defer func() { - esp.I2C0.INT_CLR.SetBits(intMask) - esp.I2C0.INT_ENA.ClearBits(intMask) - }() - - timeoutNS := int64(timeoutMS) * 1000000 - needAddress := true - needRestart := false - readLast := false - var readTo []byte - for cmdIdx, reg := 0, &esp.I2C0.COMD0; cmdIdx < len(cmd); { - c := &cmd[cmdIdx] - - switch c.cmd { - case i2cCMD_RSTART: - reg.Set(i2cCMD_RSTART) - reg = nextAddress(reg) - cmdIdx++ - - case i2cCMD_WRITE: - count := 32 - if needAddress { - needAddress = false - esp.I2C0.SetDATA_FIFO_RDATA((uint32(addr) & 0x7f) << 1) - count-- - esp.I2C0.SLAVE_ADDR.Set(uint32(addr)) - esp.I2C0.SetCTR_CONF_UPGATE(1) - } - for ; count > 0 && c.head < len(c.data); count, c.head = count-1, c.head+1 { - esp.I2C0.SetDATA_FIFO_RDATA(uint32(c.data[c.head])) - } - reg.Set(i2cCMD_WRITE | uint32(32-count)) - reg = nextAddress(reg) - - if c.head < len(c.data) { - reg.Set(i2cCMD_END) - reg = nil - } else { - cmdIdx++ - } - needRestart = true - - case i2cCMD_READ: - if needAddress { - needAddress = false - esp.I2C0.SetDATA_FIFO_RDATA((uint32(addr)&0x7f)<<1 | 1) - esp.I2C0.SLAVE_ADDR.Set(uint32(addr)) - reg.Set(i2cCMD_WRITE | 1) - reg = nextAddress(reg) - } - if needRestart { - // We need to send RESTART again after i2cCMD_WRITE. - reg.Set(i2cCMD_RSTART) - - reg = nextAddress(reg) - reg.Set(i2cCMD_WRITE | 1) - - reg = nextAddress(reg) - esp.I2C0.SetDATA_FIFO_RDATA((uint32(addr)&0x7f)<<1 | 1) - needRestart = false - } - count := 32 - bytes := len(c.data) - c.head - // Only last byte in sequence must be sent with ACK set to 1 to indicate end of data. - split := bytes <= count - if split { - bytes-- - } - if bytes > 32 { - bytes = 32 - } - reg.Set(i2cCMD_READ | uint32(bytes)) - reg = nextAddress(reg) - - if split { - readLast = true - reg.Set(i2cCMD_READLAST | 1) - reg = nextAddress(reg) - readTo = c.data[c.head : c.head+bytes+1] // read bytes + 1 last byte - cmdIdx++ - } else { - reg.Set(i2cCMD_END) - readTo = c.data[c.head : c.head+bytes] - reg = nil - } - - case i2cCMD_STOP: - reg.Set(i2cCMD_STOP) - reg = nil - cmdIdx++ - } - if reg == nil { - // transmit now - esp.I2C0.SetCTR_CONF_UPGATE(1) - esp.I2C0.SetCTR_TRANS_START(1) - end := nanotime() + timeoutNS - var mask uint32 - for mask = esp.I2C0.INT_STATUS.Get(); mask&intMask == 0; mask = esp.I2C0.INT_STATUS.Get() { - if nanotime() > end { - if readTo != nil { - return errI2CReadTimeout - } - return errI2CWriteTimeout - } - } - switch { - case mask&esp.I2C_INT_STATUS_NACK_INT_ST_Msk != 0 && !readLast: - return errI2CAckExpected - case mask&esp.I2C_INT_STATUS_TIME_OUT_INT_ST_Msk != 0: - if readTo != nil { - return errI2CReadTimeout - } - return errI2CWriteTimeout - } - esp.I2C0.INT_CLR.SetBits(intMask) - for i := 0; i < len(readTo); i++ { - readTo[i] = byte(esp.I2C0.GetDATA_FIFO_RDATA() & 0xff) - c.head++ - } - readTo = nil - reg = &esp.I2C0.COMD0 - } - } - 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) (err error) { - // timeout in microseconds. - const timeout = 40 // 40ms is a reasonable time for a real-time system. - - cmd := make([]i2cCommand, 0, 8) - cmd = append(cmd, i2cCommand{cmd: i2cCMD_RSTART}) - if len(w) > 0 { - cmd = append(cmd, i2cCommand{cmd: i2cCMD_WRITE, data: w}) - } - if len(r) > 0 { - cmd = append(cmd, i2cCommand{cmd: i2cCMD_READ, data: r}) - } - cmd = append(cmd, i2cCommand{cmd: i2cCMD_STOP}) - - return i2c.transmit(addr, cmd, timeout) -} - -func (i2c *I2C) SetBaudRate(br uint32) error { - return nil -} - -func nextAddress(reg *volatile.Register32) *volatile.Register32 { - return (*volatile.Register32)(unsafe.Add(unsafe.Pointer(reg), 4)) -} diff --git a/emb/machine/machine_esp32c3_spi.go b/emb/machine/machine_esp32c3_spi.go deleted file mode 100644 index aec3ca7..0000000 --- a/emb/machine/machine_esp32c3_spi.go +++ /dev/null @@ -1,323 +0,0 @@ -//go:build esp32c3 - -package machine - -// On the C3 variant, SPI2 is a general purpose SPI controller. SPI0 and SPI1 -// are used internally to access the ESP32-C3’s attached flash memory. Due to -// different registers between SPI2 and the other SPI ports, this driver -// currently supports only the the general purpose FSPI SPI2 controller. -// https://docs.espressif.com/projects/esp-idf/en/latest/esp32c3/api-reference/peripherals/spi_master.html - -import ( - "device/esp" - "errors" - "runtime/volatile" - "unsafe" -) - -const ( - SPI_MODE0 = uint8(0) - SPI_MODE1 = uint8(1) - SPI_MODE2 = uint8(2) - SPI_MODE3 = uint8(3) - - FSPICLK_IN_IDX = uint32(63) - FSPICLK_OUT_IDX = uint32(63) - FSPIQ_IN_IDX = uint32(64) - FSPIQ_OUT_IDX = uint32(64) - FSPID_IN_IDX = uint32(65) - FSPID_OUT_IDX = uint32(65) - FSPIHD_IN_IDX = uint32(66) - FSPIHD_OUT_IDX = uint32(66) - FSPIWP_IN_IDX = uint32(67) - FSPIWP_OUT_IDX = uint32(67) - FSPICS0_IN_IDX = uint32(68) - FSPICS0_OUT_IDX = uint32(68) - FSPICS1_OUT_IDX = uint32(69) - FSPICS2_OUT_IDX = uint32(70) - FSPICS3_OUT_IDX = uint32(71) - FSPICS4_OUT_IDX = uint32(72) - FSPICS5_OUT_IDX = uint32(73) -) - -var ( - ErrInvalidSPIBus = errors.New("machine: SPI bus is invalid") - ErrInvalidSPIMode = errors.New("machine: SPI mode is invalid") -) - -// Serial Peripheral Interface on the ESP32-C3. -type SPI struct { - Bus *esp.SPI2_Type -} - -var ( - // SPI0 and SPI1 are reserved for use by the caching system etc. - SPI2 = &SPI{esp.SPI2} -) - -// SPIConfig is used to store config info for SPI. -type SPIConfig struct { - Frequency uint32 - SCK Pin // Serial Clock - SDO Pin // Serial Data Out (MOSI) - SDI Pin // Serial Data In (MISO) - CS Pin // Chip Select (optional) - LSBFirst bool // MSB is default - Mode uint8 // SPI_MODE0 is default -} - -// Compute the SPI bus frequency from the CPU frequency. -func freqToClockDiv(hz uint32) uint32 { - fcpu := CPUFrequency() - if hz >= fcpu { // maximum frequency - return 1 << 31 - } - if hz < (fcpu / (16 * 64)) { // minimum frequency - return 15<<18 | 63<<12 | 31<<6 | 63 // pre=15, n=63 - } - - // iterate looking for an exact match - // or iterate all 16 prescaler options - // looking for the smallest error - var bestPre, bestN, bestErr uint32 - bestN = 1 - bestErr = 0xffffffff - q := uint32(float32(pplClockFreq)/float32(hz) + float32(0.5)) - for p := uint32(0); p < 16; p++ { - n := q/(p+1) - 1 - if n < 1 { // prescaler became too large, stop enum - break - } - if n > 63 { // prescaler too small, skip to next - continue - } - - freq := fcpu / ((p + 1) * (n + 1)) - if freq == hz { // exact match - return p<<18 | n<<12 | (n/2)<<6 | n - } - - var err uint32 - if freq < hz { - err = hz - freq - } else { - err = freq - hz - } - if err < bestErr { - bestErr = err - bestPre = p - bestN = n - } - } - - return bestPre<<18 | bestN<<12 | (bestN/2)<<6 | bestN -} - -// Configure and make the SPI peripheral ready to use. -func (spi *SPI) Configure(config SPIConfig) error { - // right now this is only setup to work for the esp32c3 spi2 bus - if spi.Bus != esp.SPI2 { - return ErrInvalidSPIBus - } - - // periph module reset - esp.SYSTEM.SetPERIP_RST_EN0_SPI2_RST(1) - esp.SYSTEM.SetPERIP_RST_EN0_SPI2_RST(0) - - // periph module enable - esp.SYSTEM.SetPERIP_CLK_EN0_SPI2_CLK_EN(1) - esp.SYSTEM.SetPERIP_RST_EN0_SPI2_RST(0) - - // init the spi2 bus - spi.Bus.SLAVE.Set(0) - spi.Bus.MISC.Set(0) - spi.Bus.USER.Set(0) - spi.Bus.USER1.Set(0) - spi.Bus.CTRL.Set(0) - spi.Bus.CLK_GATE.Set(0) - spi.Bus.DMA_CONF.Set(0) - spi.Bus.SetDMA_CONF_RX_AFIFO_RST(1) - spi.Bus.SetDMA_CONF_BUF_AFIFO_RST(1) - spi.Bus.CLOCK.Set(0) - - // clear data buf - spi.Bus.SetW0(0) - spi.Bus.SetW1(0) - spi.Bus.SetW2(0) - spi.Bus.SetW3(0) - spi.Bus.SetW4(0) - spi.Bus.SetW5(0) - spi.Bus.SetW6(0) - spi.Bus.SetW7(0) - spi.Bus.SetW8(0) - spi.Bus.SetW9(0) - spi.Bus.SetW10(0) - spi.Bus.SetW11(0) - spi.Bus.SetW12(0) - spi.Bus.SetW13(0) - spi.Bus.SetW14(0) - spi.Bus.SetW15(0) - - // start the spi2 bus - spi.Bus.SetCLK_GATE_CLK_EN(1) - spi.Bus.SetCLK_GATE_MST_CLK_SEL(1) - spi.Bus.SetCLK_GATE_MST_CLK_ACTIVE(1) - spi.Bus.SetDMA_CONF_SLV_TX_SEG_TRANS_CLR_EN(1) - spi.Bus.SetDMA_CONF_SLV_RX_SEG_TRANS_CLR_EN(1) - spi.Bus.SetDMA_CONF_DMA_SLV_SEG_TRANS_EN(0) - spi.Bus.SetUSER_USR_MOSI(1) - spi.Bus.SetUSER_USR_MISO(1) - spi.Bus.SetUSER_DOUTDIN(1) - - // set spi2 data mode - switch config.Mode { - case SPI_MODE0: - spi.Bus.SetMISC_CK_IDLE_EDGE(0) - spi.Bus.SetUSER_CK_OUT_EDGE(0) - case SPI_MODE1: - spi.Bus.SetMISC_CK_IDLE_EDGE(0) - spi.Bus.SetUSER_CK_OUT_EDGE(1) - case SPI_MODE2: - spi.Bus.SetMISC_CK_IDLE_EDGE(1) - spi.Bus.SetUSER_CK_OUT_EDGE(1) - case SPI_MODE3: - spi.Bus.SetMISC_CK_IDLE_EDGE(1) - spi.Bus.SetUSER_CK_OUT_EDGE(0) - default: - return ErrInvalidSPIMode - } - - // set spi2 bit order - if config.LSBFirst { - spi.Bus.SetCTRL_WR_BIT_ORDER(1) // LSB first - spi.Bus.SetCTRL_RD_BIT_ORDER(1) - } else { - spi.Bus.SetCTRL_WR_BIT_ORDER(0) // MSB first - spi.Bus.SetCTRL_RD_BIT_ORDER(0) - } - - // configure SPI bus clock - spi.Bus.CLOCK.Set(freqToClockDiv(config.Frequency)) - - // configure esp32c3 gpio pin matrix - config.SDI.Configure(PinConfig{Mode: PinInput}) - inFunc(FSPIQ_IN_IDX).Set(esp.GPIO_FUNC_IN_SEL_CFG_SEL | uint32(config.SDI)) - config.SDO.Configure(PinConfig{Mode: PinOutput}) - config.SDO.outFunc().Set(FSPID_OUT_IDX) - config.SCK.Configure(PinConfig{Mode: PinOutput}) - config.SCK.outFunc().Set(FSPICLK_OUT_IDX) - if config.CS != NoPin { - config.CS.Configure(PinConfig{Mode: PinOutput}) - config.CS.outFunc().Set(FSPICS0_OUT_IDX) - } - - return nil -} - -// Transfer writes/reads a single byte using the SPI interface. If you need to -// transfer larger amounts of data, Tx will be faster. -func (spi *SPI) Transfer(w byte) (byte, error) { - spi.Bus.SetMS_DLEN_MS_DATA_BITLEN(7) - - spi.Bus.SetW0(uint32(w)) - - // Send/receive byte. - spi.Bus.SetCMD_UPDATE(1) - for spi.Bus.GetCMD_UPDATE() != 0 { - } - - spi.Bus.SetCMD_USR(1) - for spi.Bus.GetCMD_USR() != 0 { - } - - // The received byte is stored in W0. - return byte(spi.Bus.GetW0()), nil -} - -// Tx handles read/write operation for SPI interface. Since SPI is a synchronous write/read -// interface, there must always be the same number of bytes written as bytes read. -// This is accomplished by sending zero bits if r is bigger than w or discarding -// the incoming data if w is bigger than r. -func (spi *SPI) Tx(w, r []byte) error { - toTransfer := len(w) - if len(r) > toTransfer { - toTransfer = len(r) - } - - for toTransfer > 0 { - // Chunk 64 bytes at a time. - chunkSize := toTransfer - if chunkSize > 64 { - chunkSize = 64 - } - - // Fill tx buffer. - transferWords := (*[16]volatile.Register32)(unsafe.Pointer(uintptr(unsafe.Pointer(&spi.Bus.W0)))) - if len(w) >= 64 { - // We can fill the entire 64-byte transfer buffer with data. - // This loop is slightly faster than the loop below. - for i := 0; i < 16; i++ { - word := uint32(w[i*4]) | uint32(w[i*4+1])<<8 | uint32(w[i*4+2])<<16 | uint32(w[i*4+3])<<24 - transferWords[i].Set(word) - } - } else { - // We can't fill the entire transfer buffer, so we need to be a bit - // more careful. - // Note that parts of the transfer buffer that aren't used still - // need to be set to zero, otherwise we might be transferring - // garbage from a previous transmission if w is smaller than r. - for i := 0; i < 16; i++ { - var word uint32 - if i*4+3 < len(w) { - word |= uint32(w[i*4+3]) << 24 - } - if i*4+2 < len(w) { - word |= uint32(w[i*4+2]) << 16 - } - if i*4+1 < len(w) { - word |= uint32(w[i*4+1]) << 8 - } - if i*4+0 < len(w) { - word |= uint32(w[i*4+0]) << 0 - } - transferWords[i].Set(word) - } - } - - // Do the transfer. - spi.Bus.SetMS_DLEN_MS_DATA_BITLEN(uint32(chunkSize)*8 - 1) - - spi.Bus.SetCMD_UPDATE(1) - for spi.Bus.GetCMD_UPDATE() != 0 { - } - - spi.Bus.SetCMD_USR(1) - for spi.Bus.GetCMD_USR() != 0 { - } - - // Read rx buffer. - rxSize := 64 - if rxSize > len(r) { - rxSize = len(r) - } - for i := 0; i < rxSize; i++ { - r[i] = byte(transferWords[i/4].Get() >> ((i % 4) * 8)) - } - - // Cut off some part of the output buffer so the next iteration we will - // only send the remaining bytes. - if len(w) < chunkSize { - w = nil - } else { - w = w[chunkSize:] - } - if len(r) < chunkSize { - r = nil - } else { - r = r[chunkSize:] - } - toTransfer -= chunkSize - } - - return nil -} diff --git a/emb/machine/machine_esp8266.go b/emb/machine/machine_esp8266.go deleted file mode 100644 index 4edd4a5..0000000 --- a/emb/machine/machine_esp8266.go +++ /dev/null @@ -1,194 +0,0 @@ -//go:build esp8266 - -package machine - -import ( - "device/esp" - "runtime/volatile" -) - -const deviceName = esp.Device - -func CPUFrequency() uint32 { - return 80000000 // 80MHz -} - -const ( - PinOutput PinMode = iota - PinInput -) - -// Hardware pin numbers -const ( - GPIO0 Pin = iota - GPIO1 - GPIO2 - GPIO3 - GPIO4 - GPIO5 - GPIO6 - GPIO7 - GPIO8 - GPIO9 - GPIO10 - GPIO11 - GPIO12 - GPIO13 - GPIO14 - GPIO15 - GPIO16 -) - -// Pins that are fixed by the chip. -const ( - UART_TX_PIN Pin = 1 - UART_RX_PIN Pin = 3 -) - -// Pin functions are not trivial. The below array maps a pin number (GPIO -// number) to the pad as used in the IO mux. -// Tables with the mapping: -// https://www.esp8266.com/wiki/doku.php?id=esp8266_gpio_pin_allocations#pin_functions -// https://www.espressif.com/sites/default/files/documentation/ESP8266_Pin_List_0.xls -var pinPadMapping = [...]uint8{ - 12: 0, - 13: 1, - 14: 2, - 15: 3, - 3: 4, - 1: 5, - 6: 6, - 7: 7, - 8: 8, - 9: 9, - 10: 10, - 11: 11, - 0: 12, - 2: 13, - 4: 14, - 5: 15, -} - -// getPad returns the pad number and the register to configure this pad. -func (p Pin) getPad() (uint8, *volatile.Register32) { - pad := pinPadMapping[p] - var reg *volatile.Register32 - switch pad { - case 0: - reg = &esp.IO_MUX.IO_MUX_MTDI - case 1: - reg = &esp.IO_MUX.IO_MUX_MTCK - case 2: - reg = &esp.IO_MUX.IO_MUX_MTMS - case 3: - reg = &esp.IO_MUX.IO_MUX_MTDO - case 4: - reg = &esp.IO_MUX.IO_MUX_U0RXD - case 5: - reg = &esp.IO_MUX.IO_MUX_U0TXD - case 6: - reg = &esp.IO_MUX.IO_MUX_SD_CLK - case 7: - reg = &esp.IO_MUX.IO_MUX_SD_DATA0 - case 8: - reg = &esp.IO_MUX.IO_MUX_SD_DATA1 - case 9: - reg = &esp.IO_MUX.IO_MUX_SD_DATA2 - case 10: - reg = &esp.IO_MUX.IO_MUX_SD_DATA3 - case 11: - reg = &esp.IO_MUX.IO_MUX_SD_CMD - case 12: - reg = &esp.IO_MUX.IO_MUX_GPIO0 - case 13: - reg = &esp.IO_MUX.IO_MUX_GPIO2 - case 14: - reg = &esp.IO_MUX.IO_MUX_GPIO4 - case 15: - reg = &esp.IO_MUX.IO_MUX_GPIO5 - } - return pad, reg -} - -// Configure sets the given pin as output or input pin. -func (p Pin) Configure(config PinConfig) { - switch config.Mode { - case PinInput, PinOutput: - pad, reg := p.getPad() - if pad >= 12 { // pin 0, 2, 4, 5 - reg.Set(0 << 4) // function 0 at bit position 4 - } else { - reg.Set(3 << 4) // function 3 at bit position 4 - } - if config.Mode == PinOutput { - esp.GPIO.GPIO_ENABLE_W1TS.Set(1 << p) - } else { - esp.GPIO.GPIO_ENABLE_W1TC.Set(1 << p) - } - } -} - -// Get returns the current value of a GPIO pin when the pin is configured as an -// input or as an output. -func (p Pin) Get() bool { - // See this document for details - // https://www.espressif.com/sites/default/files/documentation/esp8266-technical_reference_en.pdf - - return esp.GPIO.GPIO_IN.Get()&(1<>16)&0xff >= 128 { - // Wait until the TX buffer has room. - } - esp.UART0.UART_FIFO.Set(uint32(c)) - return nil -} - -func (uart *UART) flush() {} diff --git a/emb/machine/machine_fe310.go b/emb/machine/machine_fe310.go deleted file mode 100644 index 2f716d6..0000000 --- a/emb/machine/machine_fe310.go +++ /dev/null @@ -1,370 +0,0 @@ -//go:build fe310 - -package machine - -import ( - "device/sifive" - "runtime/interrupt" - "unsafe" -) - -const deviceName = sifive.Device - -func CPUFrequency() uint32 { - return 320000000 // 320MHz -} - -const ( - PinInput PinMode = iota - PinOutput - PinPWM - PinSPI - PinI2C = PinSPI -) - -// Configure this pin with the given configuration. -func (p Pin) Configure(config PinConfig) { - sifive.GPIO0.INPUT_EN.SetBits(1 << uint8(p)) - switch config.Mode { - case PinInput: - sifive.GPIO0.OUTPUT_EN.ClearBits(1 << uint8(p)) - case PinOutput: - sifive.GPIO0.OUTPUT_EN.SetBits(1 << uint8(p)) - case PinPWM: - sifive.GPIO0.IOF_EN.SetBits(1 << uint8(p)) - sifive.GPIO0.IOF_SEL.SetBits(1 << uint8(p)) - case PinSPI: - sifive.GPIO0.IOF_EN.SetBits(1 << uint8(p)) - sifive.GPIO0.IOF_SEL.ClearBits(1 << uint8(p)) - } -} - -// Set the pin to high or low. -func (p Pin) Set(high bool) { - if high { - sifive.GPIO0.PORT.SetBits(1 << uint8(p)) - } else { - sifive.GPIO0.PORT.ClearBits(1 << uint8(p)) - } -} - -// Get returns the current value of a GPIO pin when the pin is configured as an -// input or as an output. -func (p Pin) Get() bool { - val := sifive.GPIO0.VALUE.Get() & (1 << uint8(p)) - return (val > 0) -} - -// Return the register and mask to enable a given GPIO pin. This can be used to -// implement bit-banged drivers. -// -// Warning: only use this on an output pin! -func (p Pin) PortMaskSet() (*uint32, uint32) { - return (*uint32)(unsafe.Pointer(&sifive.GPIO0.PORT)), sifive.GPIO0.PORT.Get() | (1 << uint8(p)) -} - -// Return the register and mask to disable a given GPIO pin. This can be used to -// implement bit-banged drivers. -// -// Warning: only use this on an output pin! -func (p Pin) PortMaskClear() (*uint32, uint32) { - return (*uint32)(unsafe.Pointer(&sifive.GPIO0.PORT)), sifive.GPIO0.PORT.Get() &^ (1 << uint8(p)) -} - -type UART struct { - Bus *sifive.UART_Type - Buffer *RingBuffer -} - -var ( - UART0 = &_UART0 - _UART0 = UART{Bus: sifive.UART0, Buffer: NewRingBuffer()} -) - -func (uart *UART) Configure(config UARTConfig) { - if config.BaudRate == 0 { - config.BaudRate = 115200 - } - // The divisor is: - // fbaud = fin / (div + 1) - // Restating to get the divisor: - // div = fin / fbaud - 1 - // But we're using integers, so we should take care of rounding: - // div = (fin + fbaud/2) / fbaud - 1 - divisor := (CPUFrequency()+config.BaudRate/2)/config.BaudRate - 1 - sifive.UART0.DIV.Set(divisor) - sifive.UART0.TXCTRL.Set(sifive.UART_TXCTRL_ENABLE) - sifive.UART0.RXCTRL.Set(sifive.UART_RXCTRL_ENABLE) - sifive.UART0.IE.Set(sifive.UART_IE_RXWM) // enable the receive interrupt (only) - intr := interrupt.New(sifive.IRQ_UART0, _UART0.handleInterrupt) - intr.SetPriority(5) - intr.Enable() -} - -func (uart *UART) handleInterrupt(interrupt.Interrupt) { - rxdata := uart.Bus.RXDATA.Get() - c := byte(rxdata) - if uint32(c) != rxdata { - // The rxdata has other bits set than just the low 8 bits. This probably - // means that the 'empty' flag is set, which indicates there is no data - // to be read and the byte is garbage. Ignore this byte. - return - } - uart.Receive(c) -} - -func (uart *UART) writeByte(c byte) error { - for sifive.UART0.TXDATA.Get()&sifive.UART_TXDATA_FULL != 0 { - } - - sifive.UART0.TXDATA.Set(uint32(c)) - return nil -} - -func (uart *UART) flush() {} - -// SPI on the FE310. The normal SPI0 is actually a quad-SPI meant for flash, so it is best -// to use SPI1 or SPI2 port for most applications. -type SPI struct { - Bus *sifive.QSPI_Type -} - -// SPIConfig is used to store config info for SPI. -type SPIConfig struct { - Frequency uint32 - SCK Pin - SDO Pin - SDI Pin - LSBFirst bool - Mode uint8 -} - -// Configure is intended to setup the SPI interface. -func (spi *SPI) Configure(config SPIConfig) error { - // Use default pins if not set. - if config.SCK == 0 && config.SDO == 0 && config.SDI == 0 { - config.SCK = SPI0_SCK_PIN - config.SDO = SPI0_SDO_PIN - config.SDI = SPI0_SDI_PIN - } - - // enable pins for SPI - config.SCK.Configure(PinConfig{Mode: PinSPI}) - config.SDO.Configure(PinConfig{Mode: PinSPI}) - config.SDI.Configure(PinConfig{Mode: PinSPI}) - - // set default frequency - if config.Frequency == 0 { - config.Frequency = 4000000 // 4MHz - } - - // div = (SPI_CFG(dev)->f_sys / (2 * frequency)) - 1; - div := CPUFrequency()/(2*config.Frequency) - 1 - spi.Bus.DIV.Set(div) - - // set mode - switch config.Mode { - case 0: - spi.Bus.MODE.ClearBits(sifive.QSPI_MODE_PHASE) - spi.Bus.MODE.ClearBits(sifive.QSPI_MODE_POLARITY) - case 1: - spi.Bus.MODE.SetBits(sifive.QSPI_MODE_PHASE) - spi.Bus.MODE.ClearBits(sifive.QSPI_MODE_POLARITY) - case 2: - spi.Bus.MODE.ClearBits(sifive.QSPI_MODE_PHASE) - spi.Bus.MODE.SetBits(sifive.QSPI_MODE_POLARITY) - case 3: - spi.Bus.MODE.SetBits(sifive.QSPI_MODE_PHASE | sifive.QSPI_MODE_POLARITY) - default: // to mode 0 - spi.Bus.MODE.ClearBits(sifive.QSPI_MODE_PHASE) - spi.Bus.MODE.ClearBits(sifive.QSPI_MODE_POLARITY) - } - - // frame length - spi.Bus.FMT.SetBits(8 << sifive.QSPI_FMT_LENGTH_Pos) - - // Set single line operation, by clearing all bits - spi.Bus.FMT.ClearBits(sifive.QSPI_FMT_PROTOCOL_Msk) - - // set bit transfer order - if config.LSBFirst { - spi.Bus.FMT.SetBits(sifive.QSPI_FMT_ENDIAN) - } else { - spi.Bus.FMT.ClearBits(sifive.QSPI_FMT_ENDIAN) - } - - return nil -} - -// Transfer writes/reads a single byte using the SPI interface. -func (spi *SPI) Transfer(w byte) (byte, error) { - // wait for tx ready - for spi.Bus.TXDATA.HasBits(sifive.QSPI_TXDATA_FULL) { - } - - // write data - spi.Bus.TXDATA.Set(uint32(w)) - - // wait until receive has data - data := spi.Bus.RXDATA.Get() - for data&sifive.QSPI_RXDATA_EMPTY > 0 { - data = spi.Bus.RXDATA.Get() - } - - // return data - return byte(data), nil -} - -// I2C on the FE310-G002. -type I2C struct { - Bus sifive.I2C_Type -} - -var ( - I2C0 = (*I2C)(unsafe.Pointer(sifive.I2C0)) -) - -// I2CConfig is used to store config info for I2C. -type I2CConfig struct { - Frequency uint32 - SCL Pin - SDA Pin -} - -var i2cClockFrequency uint32 = 32000000 - -// Configure is intended to setup the I2C interface. -func (i2c *I2C) Configure(config I2CConfig) error { - if config.Frequency == 0 { - config.Frequency = 100 * KHz - } - - if config.SDA == 0 && config.SCL == 0 { - config.SDA = I2C0_SDA_PIN - config.SCL = I2C0_SCL_PIN - } - - i2c.SetBaudRate(config.Frequency) - - config.SDA.Configure(PinConfig{Mode: PinI2C}) - config.SCL.Configure(PinConfig{Mode: PinI2C}) - - return nil -} - -// SetBaudRate sets the communication speed for I2C. -func (i2c *I2C) SetBaudRate(br uint32) error { - var prescaler = i2cClockFrequency/(5*br) - 1 - - // disable controller before setting the prescale registers - i2c.Bus.CTR.ClearBits(sifive.I2C_CTR_EN) - - // set prescaler registers - i2c.Bus.PRER_LO.Set(uint32(prescaler & 0xff)) - i2c.Bus.PRER_HI.Set(uint32((prescaler >> 8) & 0xff)) - - // enable controller - i2c.Bus.CTR.SetBits(sifive.I2C_CTR_EN) - - 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 { - var err error - if len(w) != 0 { - // send start/address for write - i2c.sendAddress(addr, true) - - // ACK received (0: ACK, 1: NACK) - if i2c.Bus.CR_SR.HasBits(sifive.I2C_SR_RX_ACK) { - return errI2CAckExpected - } - - // write data - for _, b := range w { - err = i2c.writeByte(b) - if err != nil { - return err - } - } - } - if len(r) != 0 { - // send start/address for read - i2c.sendAddress(addr, false) - - // ACK received (0: ACK, 1: NACK) - if i2c.Bus.CR_SR.HasBits(sifive.I2C_SR_RX_ACK) { - return errI2CAckExpected - } - - // read first byte - r[0] = i2c.readByte() - for i := 1; i < len(r); i++ { - // send an ACK - i2c.Bus.CR_SR.Set(^uint32(sifive.I2C_CR_ACK)) - - // read data and send the ACK - r[i] = i2c.readByte() - } - - // send NACK to end transmission - i2c.Bus.CR_SR.Set(sifive.I2C_CR_ACK) - } - - // generate stop condition - i2c.Bus.CR_SR.Set(sifive.I2C_CR_STO) - return nil -} - -// Writes a single byte to the I2C bus. -func (i2c *I2C) writeByte(data byte) error { - // Send data byte - i2c.Bus.TXR_RXR.Set(uint32(data)) - - i2c.Bus.CR_SR.Set(sifive.I2C_CR_WR) - - // wait until transmission complete - for i2c.Bus.CR_SR.HasBits(sifive.I2C_SR_TIP) { - } - - // ACK received (0: ACK, 1: NACK) - if i2c.Bus.CR_SR.HasBits(sifive.I2C_SR_RX_ACK) { - return errI2CAckExpected - } - - return nil -} - -// Reads a single byte from the I2C bus. -func (i2c *I2C) readByte() byte { - i2c.Bus.CR_SR.Set(sifive.I2C_CR_RD) - - // wait until transmission complete - for i2c.Bus.CR_SR.HasBits(sifive.I2C_SR_TIP) { - } - - return byte(i2c.Bus.TXR_RXR.Get()) -} - -// Sends the address and start signal. -func (i2c *I2C) sendAddress(address uint16, write bool) error { - data := (address << 1) - if !write { - data |= 1 // set read flag in transmit register - } - - // write address to transmit register - i2c.Bus.TXR_RXR.Set(uint32(data)) - - // generate start condition - i2c.Bus.CR_SR.Set((sifive.I2C_CR_STA | sifive.I2C_CR_WR)) - - // wait until transmission complete - for i2c.Bus.CR_SR.HasBits(sifive.I2C_SR_TIP) { - } - - return nil -} diff --git a/emb/machine/machine_gameboyadvance.go b/emb/machine/machine_gameboyadvance.go deleted file mode 100644 index a5c0c06..0000000 --- a/emb/machine/machine_gameboyadvance.go +++ /dev/null @@ -1,64 +0,0 @@ -//go:build gameboyadvance - -package machine - -import ( - "device/gba" - - "image/color" - "runtime/volatile" - "unsafe" -) - -// Not sure what name to pick here. Not using ARM7TDMI because that's the CPU -// name, not the device name. -const deviceName = "GBA" - -// Interrupt numbers as used on the GameBoy Advance. Register them with -// runtime/interrupt.New. -const ( - IRQ_VBLANK = gba.IRQ_VBLANK - IRQ_HBLANK = gba.IRQ_HBLANK - IRQ_VCOUNT = gba.IRQ_VCOUNT - IRQ_TIMER0 = gba.IRQ_TIMER0 - IRQ_TIMER1 = gba.IRQ_TIMER1 - IRQ_TIMER2 = gba.IRQ_TIMER2 - IRQ_TIMER3 = gba.IRQ_TIMER3 - IRQ_COM = gba.IRQ_COM - IRQ_DMA0 = gba.IRQ_DMA0 - IRQ_DMA1 = gba.IRQ_DMA1 - IRQ_DMA2 = gba.IRQ_DMA2 - IRQ_DMA3 = gba.IRQ_DMA3 - IRQ_KEYPAD = gba.IRQ_KEYPAD - IRQ_GAMEPAK = gba.IRQ_GAMEPAK -) - -// Set has not been implemented. -func (p Pin) Set(value bool) { - // do nothing -} - -var Display = DisplayMode3{(*[160][240]volatile.Register16)(unsafe.Pointer(uintptr(gba.MEM_VRAM)))} - -type DisplayMode3 struct { - port *[160][240]volatile.Register16 -} - -func (d *DisplayMode3) Configure() { - // Use video mode 3 (in BG2, a 16bpp bitmap in VRAM) and Enable BG2 - gba.DISP.DISPCNT.Set(gba.DISPCNT_BGMODE_3<> 3) | ((uint16(c.G) >> 3) << 5) | ((uint16(c.B) >> 3) << 10)) -} - -func (d *DisplayMode3) Display() error { - // Nothing to do here. - return nil -} diff --git a/emb/machine/machine_generic.go b/emb/machine/machine_generic.go deleted file mode 100644 index 82206f9..0000000 --- a/emb/machine/machine_generic.go +++ /dev/null @@ -1,367 +0,0 @@ -//go:build !baremetal - -package machine - -import ( - "crypto/rand" - _ "unsafe" -) - -// Dummy machine package that calls out to external functions. - -const deviceName = "generic" - -var ( - USB = &UART{100} -) - -// The Serial port always points to the default UART in a simulated environment. -// -// TODO: perhaps this should be a special serial object that outputs via WASI -// stdout calls. -var Serial = hardwareUART0 - -const ( - PinInput PinMode = iota - PinOutput - PinInputPullup - PinInputPulldown -) - -func (p Pin) Configure(config PinConfig) { - gpioConfigure(p, config) -} - -func (p Pin) Set(value bool) { - gpioSet(p, value) -} - -func (p Pin) Get() bool { - return gpioGet(p) -} - -//go:linkname gpioConfigure __llgo_gpio_configure -func gpioConfigure(pin Pin, config PinConfig) - -//go:linkname gpioSet __llgo_gpio_set -func gpioSet(pin Pin, value bool) - -//go:linkname gpioGet __llgo_gpio_get -func gpioGet(pin Pin) bool - -// Generic PWM/timer peripheral. Properties can be configured depending on the -// hardware. -type timerType struct { - // Static properties. - instance int32 - frequency uint64 - bits int - prescalers []int - channelPins [][]Pin - - // Configured 'top' value. - top uint32 -} - -// Configure the PWM/timer peripheral. -func (t *timerType) Configure(config PWMConfig) error { - // Note: for very large period values, this multiplication will overflow. - top := config.Period * t.frequency / 1e9 - if config.Period == 0 { - top = 0xffff // default for LEDs - } - - // The maximum value that can be stored with the given number of bits in - // this timer. - maxTop := uint64(1)< FUNC_GPIO7 { - return // The pin is not configured as GPIO or GPIOHS. - } - - // Configure pin. - kendryte.FPIOA.IO[uint8(p)].SetBits(kendryte.FPIOA_IO_OE_EN | kendryte.FPIOA_IO_IE_EN | kendryte.FPIOA_IO_ST | kendryte.FPIOA_IO_DS_Msk) - - switch config.Mode { - case PinInput: - p.setFPIOAIOPull(fpioaPullNone) - input = true - case PinInputPullup: - p.setFPIOAIOPull(fpioaPullUp) - input = true - case PinInputPulldown: - p.setFPIOAIOPull(fpioaPullDown) - input = true - case PinOutput: - p.setFPIOAIOPull(fpioaPullNone) - input = false - } - - if f >= FUNC_GPIO0 && f <= FUNC_GPIO7 { - // Converts the IO pin number in the effective GPIO number (based on the FPIOA function). - gpioPin := uint8(f - FUNC_GPIO0) - - if input { - kendryte.GPIO.DIRECTION.ClearBits(1 << gpioPin) - } else { - kendryte.GPIO.DIRECTION.SetBits(1 << gpioPin) - } - } else if f >= FUNC_GPIOHS0 && f <= FUNC_GPIOHS31 { - // Converts the IO pin number in the effective GPIOHS number (based on the FPIOA function). - gpioPin := uint8(f - FUNC_GPIOHS0) - - if input { - kendryte.GPIOHS.INPUT_EN.SetBits(1 << gpioPin) - kendryte.GPIOHS.OUTPUT_EN.ClearBits(1 << gpioPin) - } else { - kendryte.GPIOHS.OUTPUT_EN.SetBits(1 << gpioPin) - kendryte.GPIOHS.INPUT_EN.ClearBits(1 << gpioPin) - } - } -} - -// Set the pin to high or low. -func (p Pin) Set(high bool) { - - // Check if the current pin's FPIOA function is either GPIO or GPIOHS. - f := p.FPIOAFunction() - if f < FUNC_GPIOHS0 || f > FUNC_GPIO7 { - return // The pin is not configured as GPIO or GPIOHS. - } - - if f >= FUNC_GPIO0 && f <= FUNC_GPIO7 { - gpioPin := uint8(f - FUNC_GPIO0) - - if high { - kendryte.GPIO.DATA_OUTPUT.SetBits(1 << gpioPin) - } else { - kendryte.GPIO.DATA_OUTPUT.ClearBits(1 << gpioPin) - } - } else if f >= FUNC_GPIOHS0 && f <= FUNC_GPIOHS31 { - gpioPin := uint8(f - FUNC_GPIOHS0) - - if high { - kendryte.GPIOHS.OUTPUT_VAL.SetBits(1 << gpioPin) - } else { - kendryte.GPIOHS.OUTPUT_VAL.ClearBits(1 << gpioPin) - } - } -} - -// Get returns the current value of a GPIO pin. -func (p Pin) Get() bool { - - // Check if the current pin's FPIOA function is either GPIO or GPIOHS. - f := p.FPIOAFunction() - if f < FUNC_GPIOHS0 || f > FUNC_GPIO7 { - return false // The pin is not configured as GPIO or GPIOHS. - } - - var val uint32 - if f >= FUNC_GPIO0 && f <= FUNC_GPIO7 { - gpioPin := uint8(f - FUNC_GPIO0) - val = kendryte.GPIO.DATA_INPUT.Get() & (1 << gpioPin) - } else if f >= FUNC_GPIOHS0 && f <= FUNC_GPIOHS31 { - gpioPin := uint8(f - FUNC_GPIOHS0) - val = kendryte.GPIOHS.INPUT_VAL.Get() & (1 << gpioPin) - } - return (val > 0) -} - -// Callbacks to be called for GPIOHS pins configured with SetInterrupt. -var pinCallbacks [32]func(Pin) - -// SetInterrupt sets an interrupt to be executed when a particular pin changes -// state. The pin should already be configured as an input, including a pull up -// or down if no external pull is provided. -// -// You can pass a nil func to unset the pin change interrupt. If you do so, -// the change parameter is ignored and can be set to any value (such as 0). -// If the pin is already configured with a callback, you must first unset -// this pins interrupt before you can set a new callback. -func (p Pin) SetInterrupt(change PinChange, callback func(Pin)) error { - - // Check if the pin is a GPIOHS pin. - f := p.FPIOAFunction() - if f < FUNC_GPIOHS0 || f > FUNC_GPIOHS31 { - return ErrInvalidDataPin - } - - gpioPin := uint8(f - FUNC_GPIOHS0) - - // Clear all interrupts. - kendryte.GPIOHS.RISE_IE.ClearBits(1 << gpioPin) - kendryte.GPIOHS.FALL_IE.ClearBits(1 << gpioPin) - kendryte.GPIOHS.HIGH_IE.ClearBits(1 << gpioPin) - kendryte.GPIOHS.LOW_IE.ClearBits(1 << gpioPin) - - // Clear all the pending bits for this pin. - kendryte.GPIOHS.RISE_IP.SetBits(1 << gpioPin) - kendryte.GPIOHS.FALL_IP.SetBits(1 << gpioPin) - kendryte.GPIOHS.HIGH_IP.SetBits(1 << gpioPin) - kendryte.GPIOHS.LOW_IP.SetBits(1 << gpioPin) - - if callback == nil { - if pinCallbacks[gpioPin] != nil { - pinCallbacks[gpioPin] = nil - } - return nil - } - - if pinCallbacks[gpioPin] != nil { - // The pin was already configured. - // To properly re-configure a pin, unset it first and set a new - // configuration. - return ErrNoPinChangeChannel - } - - pinCallbacks[gpioPin] = callback - - // Enable interrupts. - if change&PinRising != 0 { - kendryte.GPIOHS.RISE_IE.SetBits(1 << gpioPin) - } - if change&PinFalling != 0 { - kendryte.GPIOHS.FALL_IE.SetBits(1 << gpioPin) - } - - handleInterrupt := func(inter interrupt.Interrupt) { - - pin := uint8(inter.GetNumber() - kendryte.IRQ_GPIOHS0) - - if kendryte.GPIOHS.RISE_IE.HasBits(1 << pin) { - kendryte.GPIOHS.RISE_IE.ClearBits(1 << pin) - // Acknowledge interrupt atomically. - riscv.AsmFull( - "amoor.w {}, {mask}, ({reg})", - map[string]interface{}{ - "mask": uint32(1 << pin), - "reg": uintptr(unsafe.Pointer(&kendryte.GPIOHS.RISE_IP.Reg)), - }) - kendryte.GPIOHS.RISE_IE.SetBits(1 << pin) - } - - if kendryte.GPIOHS.FALL_IE.HasBits(1 << pin) { - kendryte.GPIOHS.FALL_IE.ClearBits(1 << pin) - // Acknowledge interrupt atomically. - riscv.AsmFull( - "amoor.w {}, {mask}, ({reg})", - map[string]interface{}{ - "mask": uint32(1 << pin), - "reg": uintptr(unsafe.Pointer(&kendryte.GPIOHS.FALL_IP.Reg)), - }) - kendryte.GPIOHS.FALL_IE.SetBits(1 << pin) - } - - pinCallbacks[pin](Pin(pin)) - } - - var ir interrupt.Interrupt - - switch f { - case FUNC_GPIOHS0: - ir = interrupt.New(kendryte.IRQ_GPIOHS0, handleInterrupt) - case FUNC_GPIOHS1: - ir = interrupt.New(kendryte.IRQ_GPIOHS1, handleInterrupt) - case FUNC_GPIOHS2: - ir = interrupt.New(kendryte.IRQ_GPIOHS2, handleInterrupt) - case FUNC_GPIOHS3: - ir = interrupt.New(kendryte.IRQ_GPIOHS3, handleInterrupt) - case FUNC_GPIOHS4: - ir = interrupt.New(kendryte.IRQ_GPIOHS4, handleInterrupt) - case FUNC_GPIOHS5: - ir = interrupt.New(kendryte.IRQ_GPIOHS5, handleInterrupt) - case FUNC_GPIOHS6: - ir = interrupt.New(kendryte.IRQ_GPIOHS6, handleInterrupt) - case FUNC_GPIOHS7: - ir = interrupt.New(kendryte.IRQ_GPIOHS7, handleInterrupt) - case FUNC_GPIOHS8: - ir = interrupt.New(kendryte.IRQ_GPIOHS8, handleInterrupt) - case FUNC_GPIOHS9: - ir = interrupt.New(kendryte.IRQ_GPIOHS9, handleInterrupt) - case FUNC_GPIOHS10: - ir = interrupt.New(kendryte.IRQ_GPIOHS10, handleInterrupt) - case FUNC_GPIOHS11: - ir = interrupt.New(kendryte.IRQ_GPIOHS11, handleInterrupt) - case FUNC_GPIOHS12: - ir = interrupt.New(kendryte.IRQ_GPIOHS12, handleInterrupt) - case FUNC_GPIOHS13: - ir = interrupt.New(kendryte.IRQ_GPIOHS13, handleInterrupt) - case FUNC_GPIOHS14: - ir = interrupt.New(kendryte.IRQ_GPIOHS14, handleInterrupt) - case FUNC_GPIOHS15: - ir = interrupt.New(kendryte.IRQ_GPIOHS15, handleInterrupt) - case FUNC_GPIOHS16: - ir = interrupt.New(kendryte.IRQ_GPIOHS16, handleInterrupt) - case FUNC_GPIOHS17: - ir = interrupt.New(kendryte.IRQ_GPIOHS17, handleInterrupt) - case FUNC_GPIOHS18: - ir = interrupt.New(kendryte.IRQ_GPIOHS18, handleInterrupt) - case FUNC_GPIOHS19: - ir = interrupt.New(kendryte.IRQ_GPIOHS19, handleInterrupt) - case FUNC_GPIOHS20: - ir = interrupt.New(kendryte.IRQ_GPIOHS20, handleInterrupt) - case FUNC_GPIOHS21: - ir = interrupt.New(kendryte.IRQ_GPIOHS21, handleInterrupt) - case FUNC_GPIOHS22: - ir = interrupt.New(kendryte.IRQ_GPIOHS22, handleInterrupt) - case FUNC_GPIOHS23: - ir = interrupt.New(kendryte.IRQ_GPIOHS23, handleInterrupt) - case FUNC_GPIOHS24: - ir = interrupt.New(kendryte.IRQ_GPIOHS24, handleInterrupt) - case FUNC_GPIOHS25: - ir = interrupt.New(kendryte.IRQ_GPIOHS25, handleInterrupt) - case FUNC_GPIOHS26: - ir = interrupt.New(kendryte.IRQ_GPIOHS26, handleInterrupt) - case FUNC_GPIOHS27: - ir = interrupt.New(kendryte.IRQ_GPIOHS27, handleInterrupt) - case FUNC_GPIOHS28: - ir = interrupt.New(kendryte.IRQ_GPIOHS28, handleInterrupt) - case FUNC_GPIOHS29: - ir = interrupt.New(kendryte.IRQ_GPIOHS29, handleInterrupt) - case FUNC_GPIOHS30: - ir = interrupt.New(kendryte.IRQ_GPIOHS30, handleInterrupt) - case FUNC_GPIOHS31: - ir = interrupt.New(kendryte.IRQ_GPIOHS31, handleInterrupt) - } - - ir.SetPriority(5) - ir.Enable() - - return nil - -} - -type UART struct { - Bus *kendryte.UARTHS_Type - Buffer *RingBuffer -} - -var ( - UART0 = &_UART0 - _UART0 = UART{Bus: kendryte.UARTHS, Buffer: NewRingBuffer()} -) - -func (uart *UART) Configure(config UARTConfig) { - - // Use default baudrate if not set. - if config.BaudRate == 0 { - config.BaudRate = 115200 - } - - // Use default pins if not set. - if config.TX == 0 && config.RX == 0 { - config.TX = UART_TX_PIN - config.RX = UART_RX_PIN - } - - config.TX.SetFPIOAFunction(FUNC_UARTHS_TX) - config.RX.SetFPIOAFunction(FUNC_UARTHS_RX) - - div := CPUFrequency()/config.BaudRate - 1 - - uart.Bus.DIV.Set(div) - uart.Bus.TXCTRL.Set(kendryte.UARTHS_TXCTRL_TXEN) - uart.Bus.RXCTRL.Set(kendryte.UARTHS_RXCTRL_RXEN) - - // Enable interrupts on receive. - uart.Bus.IE.Set(kendryte.UARTHS_IE_RXWM) - - intr := interrupt.New(kendryte.IRQ_UARTHS, _UART0.handleInterrupt) - intr.SetPriority(5) - intr.Enable() -} - -func (uart *UART) handleInterrupt(interrupt.Interrupt) { - rxdata := uart.Bus.RXDATA.Get() - c := byte(rxdata) - if uint32(c) != rxdata { - // The rxdata has other bits set than just the low 8 bits. This probably - // means that the 'empty' flag is set, which indicates there is no data - // to be read and the byte is garbage. Ignore this byte. - return - } - uart.Receive(c) -} - -func (uart *UART) writeByte(c byte) error { - for uart.Bus.TXDATA.Get()&kendryte.UARTHS_TXDATA_FULL != 0 { - } - - uart.Bus.TXDATA.Set(uint32(c)) - return nil -} - -func (uart *UART) flush() {} - -type SPI struct { - Bus *kendryte.SPI_Type -} - -// SPIConfig is used to store config info for SPI. -type SPIConfig struct { - Frequency uint32 - SCK Pin - SDO Pin - SDI Pin - LSBFirst bool - Mode uint8 -} - -// Configure is intended to setup the SPI interface. -// Only SPI controller 0 and 1 can be used because SPI2 is a special -// peripheral-mode controller and SPI3 is used for flashing. -func (spi *SPI) Configure(config SPIConfig) error { - // Use default pins if not set. - if config.SCK == 0 && config.SDO == 0 && config.SDI == 0 { - config.SCK = SPI0_SCK_PIN - config.SDO = SPI0_SDO_PIN - config.SDI = SPI0_SDI_PIN - } - - // Enable APB2 clock. - kendryte.SYSCTL.CLK_EN_CENT.SetBits(kendryte.SYSCTL_CLK_EN_CENT_APB2_CLK_EN) - - switch spi.Bus { - case kendryte.SPI0: - // Initialize SPI clock. - kendryte.SYSCTL.CLK_EN_PERI.SetBits(kendryte.SYSCTL_CLK_EN_PERI_SPI0_CLK_EN) - kendryte.SYSCTL.CLK_TH1.ClearBits(kendryte.SYSCTL_CLK_TH1_SPI0_CLK_Msk) - - // Initialize pins. - config.SCK.SetFPIOAFunction(FUNC_SPI0_SCLK) - config.SDO.SetFPIOAFunction(FUNC_SPI0_D0) - config.SDI.SetFPIOAFunction(FUNC_SPI0_D1) - case kendryte.SPI1: - // Initialize SPI clock. - kendryte.SYSCTL.CLK_EN_PERI.SetBits(kendryte.SYSCTL_CLK_EN_PERI_SPI1_CLK_EN) - kendryte.SYSCTL.CLK_TH1.ClearBits(kendryte.SYSCTL_CLK_TH1_SPI1_CLK_Msk) - - // Initialize pins. - config.SCK.SetFPIOAFunction(FUNC_SPI1_SCLK) - config.SDO.SetFPIOAFunction(FUNC_SPI1_D0) - config.SDI.SetFPIOAFunction(FUNC_SPI1_D1) - default: - return errUnsupportedSPIController - } - - // Set default frequency. - if config.Frequency == 0 { - config.Frequency = 4000000 // 4MHz - } - - baudr := CPUFrequency() / config.Frequency - spi.Bus.BAUDR.Set(baudr) - - // Configure SPI mode 0, standard frame format, 8-bit data, little-endian. - spi.Bus.IMR.Set(0) - spi.Bus.DMACR.Set(0) - spi.Bus.DMATDLR.Set(0x10) - spi.Bus.DMARDLR.Set(0) - spi.Bus.SER.Set(0) - spi.Bus.SSIENR.Set(0) - spi.Bus.CTRLR0.Set((7 << 16)) - spi.Bus.SPI_CTRLR0.Set(0) - spi.Bus.ENDIAN.Set(0) - - return nil -} - -// Transfer writes/reads a single byte using the SPI interface. -func (spi *SPI) Transfer(w byte) (byte, error) { - spi.Bus.SSIENR.Set(0) - - // Set transfer-receive mode. - spi.Bus.CTRLR0.ClearBits(0x3 << 8) - - // Enable/disable SPI. - spi.Bus.SSIENR.Set(1) - defer spi.Bus.SSIENR.Set(0) - - // Enable/disable device. - spi.Bus.SER.Set(0x1) - defer spi.Bus.SER.Set(0) - - spi.Bus.DR0.Set(uint32(w)) - - // Wait for transfer. - for spi.Bus.SR.Get()&0x05 != 0x04 { - } - - // Wait for data. - for spi.Bus.RXFLR.Get() == 0 { - } - - return byte(spi.Bus.DR0.Get()), nil -} - -// I2C on the K210. -type I2C struct { - Bus kendryte.I2C_Type -} - -var ( - I2C0 = (*I2C)(unsafe.Pointer(kendryte.I2C0)) - I2C1 = (*I2C)(unsafe.Pointer(kendryte.I2C1)) - I2C2 = (*I2C)(unsafe.Pointer(kendryte.I2C2)) -) - -// I2CConfig is used to store config info for I2C. -type I2CConfig struct { - Frequency uint32 - SCL Pin - SDA Pin -} - -// Configure is intended to setup the I2C interface. -func (i2c *I2C) Configure(config I2CConfig) error { - - if config.Frequency == 0 { - config.Frequency = 100 * KHz - } - - if config.SDA == 0 && config.SCL == 0 { - config.SDA = I2C0_SDA_PIN - config.SCL = I2C0_SCL_PIN - } - - // Enable APB0 clock. - kendryte.SYSCTL.CLK_EN_CENT.SetBits(kendryte.SYSCTL_CLK_EN_CENT_APB0_CLK_EN) - - switch &i2c.Bus { - case kendryte.I2C0: - // Initialize I2C0 clock. - kendryte.SYSCTL.CLK_EN_PERI.SetBits(kendryte.SYSCTL_CLK_EN_PERI_I2C0_CLK_EN) - kendryte.SYSCTL.CLK_TH5.ReplaceBits(0x03, kendryte.SYSCTL_CLK_TH5_I2C0_CLK_Msk, kendryte.SYSCTL_CLK_TH5_I2C0_CLK_Pos) - - // Initialize pins. - config.SDA.SetFPIOAFunction(FUNC_I2C0_SDA) - config.SCL.SetFPIOAFunction(FUNC_I2C0_SCLK) - case kendryte.I2C1: - // Initialize I2C1 clock. - kendryte.SYSCTL.CLK_EN_PERI.SetBits(kendryte.SYSCTL_CLK_EN_PERI_I2C1_CLK_EN) - kendryte.SYSCTL.CLK_TH5.ReplaceBits(0x03, kendryte.SYSCTL_CLK_TH5_I2C1_CLK_Msk, kendryte.SYSCTL_CLK_TH5_I2C1_CLK_Pos) - - // Initialize pins. - config.SDA.SetFPIOAFunction(FUNC_I2C1_SDA) - config.SCL.SetFPIOAFunction(FUNC_I2C1_SCLK) - case kendryte.I2C2: - // Initialize I2C2 clock. - kendryte.SYSCTL.CLK_EN_PERI.SetBits(kendryte.SYSCTL_CLK_EN_PERI_I2C2_CLK_EN) - kendryte.SYSCTL.CLK_TH5.ReplaceBits(0x03, kendryte.SYSCTL_CLK_TH5_I2C2_CLK_Msk, kendryte.SYSCTL_CLK_TH5_I2C2_CLK_Pos) - - // Initialize pins. - config.SDA.SetFPIOAFunction(FUNC_I2C2_SDA) - config.SCL.SetFPIOAFunction(FUNC_I2C2_SCLK) - } - - i2c.SetBaudRate(config.Frequency) - - i2c.Bus.INTR_MASK.Set(0) - i2c.Bus.DMA_CR.Set(0x03) - i2c.Bus.DMA_RDLR.Set(0) - i2c.Bus.DMA_TDLR.Set(0x4) - - return nil -} - -// SetBaudRate sets the communication speed for I2C. -func (i2c *I2C) SetBaudRate(br uint32) error { - div := CPUFrequency() / br / 16 - - // Disable controller before setting the prescale register. - i2c.Bus.ENABLE.Set(0) - - i2c.Bus.CON.Set(0x63) - - // Set prescaler registers. - i2c.Bus.SS_SCL_HCNT.Set(uint32(div)) - i2c.Bus.SS_SCL_LCNT.Set(uint32(div)) - - 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 { - // Set peripheral address. - i2c.Bus.TAR.Set(uint32(addr)) - // Enable controller. - i2c.Bus.ENABLE.Set(1) - - if len(w) != 0 { - i2c.Bus.CLR_TX_ABRT.Set(i2c.Bus.CLR_TX_ABRT.Get()) - dataLen := uint32(len(w)) - di := 0 - - for dataLen != 0 { - fifoLen := 8 - i2c.Bus.TXFLR.Get() - if dataLen < fifoLen { - fifoLen = dataLen - } - - for i := uint32(0); i < fifoLen; i++ { - i2c.Bus.DATA_CMD.Set(uint32(w[di])) - di += 1 - } - if i2c.Bus.TX_ABRT_SOURCE.Get() != 0 { - return errI2CTxAbort - } - dataLen -= fifoLen - } - - // Wait for transmission to complete. - for i2c.Bus.STATUS.HasBits(kendryte.I2C_STATUS_ACTIVITY) || !i2c.Bus.STATUS.HasBits(kendryte.I2C_STATUS_TFE) { - } - - if i2c.Bus.TX_ABRT_SOURCE.Get() != 0 { - return errI2CTxAbort - } - } - if len(r) != 0 { - dataLen := uint32(len(r)) - cmdLen := uint32(len(r)) - di := 0 - - for dataLen != 0 || cmdLen != 0 { - fifoLen := i2c.Bus.RXFLR.Get() - if dataLen < fifoLen { - fifoLen = dataLen - } - for i := uint32(0); i < fifoLen; i++ { - r[di] = byte(i2c.Bus.DATA_CMD.Get()) - di += 1 - } - dataLen -= fifoLen - - fifoLen = 8 - i2c.Bus.TXFLR.Get() - if cmdLen < fifoLen { - fifoLen = cmdLen - } - for i := uint32(0); i < fifoLen; i++ { - i2c.Bus.DATA_CMD.Set(0x100) - } - if i2c.Bus.TX_ABRT_SOURCE.Get() != 0 { - return errI2CTxAbort - } - cmdLen -= fifoLen - } - } - - return nil -} diff --git a/emb/machine/machine_mimxrt1062.go b/emb/machine/machine_mimxrt1062.go deleted file mode 100644 index 74d01c7..0000000 --- a/emb/machine/machine_mimxrt1062.go +++ /dev/null @@ -1,1064 +0,0 @@ -//go:build mimxrt1062 - -package machine - -import ( - "device/nxp" - "math/bits" - "runtime/interrupt" - "runtime/volatile" -) - -// Peripheral abstraction layer for the MIMXRT1062 - -const deviceName = nxp.Device - -func CPUFrequency() uint32 { - return 600000000 -} - -const ( - // GPIO - PinInput PinMode = iota - PinInputPullup - PinInputPulldown - PinOutput - PinOutputOpenDrain - PinDisable - - // ADC - PinInputAnalog - - // UART - PinModeUARTTX - PinModeUARTRX - - // SPI - PinModeSPISDI - PinModeSPISDO - PinModeSPICLK - PinModeSPICS - - // I2C - PinModeI2CSDA - PinModeI2CSCL -) - -// Deprecated: use PinInputPullup and PinInputPulldown instead. -const ( - PinInputPullUp = PinInputPullup - PinInputPullDown = PinInputPulldown -) - -type PinChange uint8 - -const ( - PinRising PinChange = iota + 2 - PinFalling - PinToggle -) - -// pinJumpTable represents a function lookup table for all 128 GPIO pins. -// -// There are 4 GPIO ports (A-D) and 32 pins (0-31) on each port. The uint8 value -// of a Pin is used as table index. The number of pins with a defined (non-nil) -// function is recorded in the uint8 field numDefined. -type pinJumpTable struct { - lut [4 * 32]func(Pin) - numDefined uint8 -} - -// pinISR stores the interrupt callbacks for GPIO pins, and pinInterrupt holds -// an interrupt service routine that dispatches the interrupt callbacks. -var ( - pinISR pinJumpTable - pinInterrupt *interrupt.Interrupt -) - -// From the i.MXRT1062 Processor Reference Manual (Chapter 12 - GPIO): -// -// | High-speed GPIOs exist in this device: -// | - GPIO1-5 are standard-speed GPIOs that run off the IPG_CLK_ROOT, while -// | GPIO6-9 are high-speed GPIOs that run at the AHB_CLK_ROOT frequency. -// | See the table "System Clocks, Gating, and Override" in CCM chapter. -// | - Regular GPIO and high speed GPIO are paired (GPIO1 and GPIO6 share the -// | same pins, GPIO2 and GPIO7 share, etc). The IOMUXC_GPR_GPR26-29 -// | registers are used to determine if the regular or high-speed GPIO -// | module is used for the GPIO pins on a given port. -// -// Therefore, we do not even use GPIO1-5 and instead use their high-speed -// partner for all pins. This is configured at startup in the runtime package -// (func initPins() in `runtime_mimxrt1062.go`). -// We cannot declare 32 pins for all available ports (GPIO1-9) anyway, since Pin -// is only uint8, and 9*32=288 > 256, so something has to be sacrificed. - -const ( - portA Pin = iota * 32 // GPIO1(6) - portB // GPIO2(7) - portC // GPIO3(8) - portD // GPIO4(9) -) - -const ( - // [Pad]: Alt Func 0 Alt Func 1 Alt Func 2 Alt Func 3 Alt Func 4 Alt Func 5 Alt Func 6 Alt Func 7 Alt Func 8 Alt Func 9 - // ---------- --------------- --------------- ------------------- -------------------- -------------------- ----------- -------------------- -------------------- --------------------- ---------------- - PA0 = portA + 0 // [AD_B0_00]: FLEXPWM2_PWMA03 XBAR1_INOUT14 REF_CLK_32K USB_OTG2_ID LPI2C1_SCLS GPIO1_IO00 USDHC1_RESET_B LPSPI3_SCK ~ ~ - PA1 = portA + 1 // [AD_B0_01]: FLEXPWM2_PWMB03 XBAR1_INOUT15 REF_CLK_24M USB_OTG1_ID LPI2C1_SDAS GPIO1_IO01 EWM_OUT_B LPSPI3_SDO ~ ~ - PA2 = portA + 2 // [AD_B0_02]: FLEXCAN2_TX XBAR1_INOUT16 LPUART6_TX USB_OTG1_PWR FLEXPWM1_PWMX00 GPIO1_IO02 LPI2C1_HREQ LPSPI3_SDI ~ ~ - PA3 = portA + 3 // [AD_B0_03]: FLEXCAN2_RX XBAR1_INOUT17 LPUART6_RX USB_OTG1_OC FLEXPWM1_PWMX01 GPIO1_IO03 REF_CLK_24M LPSPI3_PCS0 ~ ~ - PA4 = portA + 4 // [AD_B0_04]: SRC_BOOT_MODE00 MQS_RIGHT ENET_TX_DATA03 SAI2_TX_SYNC CSI_DATA09 GPIO1_IO04 PIT_TRIGGER00 LPSPI3_PCS1 ~ ~ - PA5 = portA + 5 // [AD_B0_05]: SRC_BOOT_MODE01 MQS_LEFT ENET_TX_DATA02 SAI2_TX_BCLK CSI_DATA08 GPIO1_IO05 XBAR1_INOUT17 LPSPI3_PCS2 ~ ~ - PA6 = portA + 6 // [AD_B0_06]: JTAG_TMS GPT2_COMPARE1 ENET_RX_CLK SAI2_RX_BCLK CSI_DATA07 GPIO1_IO06 XBAR1_INOUT18 LPSPI3_PCS3 ~ ~ - PA7 = portA + 7 // [AD_B0_07]: JTAG_TCK GPT2_COMPARE2 ENET_TX_ER SAI2_RX_SYNC CSI_DATA06 GPIO1_IO07 XBAR1_INOUT19 ENET_1588_EVENT3_OUT ~ ~ - PA8 = portA + 8 // [AD_B0_08]: JTAG_MOD GPT2_COMPARE3 ENET_RX_DATA03 SAI2_RX_DATA CSI_DATA05 GPIO1_IO08 XBAR1_IN20 ENET_1588_EVENT3_IN ~ ~ - PA9 = portA + 9 // [AD_B0_09]: JTAG_TDI FLEXPWM2_PWMA03 ENET_RX_DATA02 SAI2_TX_DATA CSI_DATA04 GPIO1_IO09 XBAR1_IN21 GPT2_CLK SEMC_DQS4 ~ - PA10 = portA + 10 // [AD_B0_10]: JTAG_TDO FLEXPWM1_PWMA03 ENET_CRS SAI2_MCLK CSI_DATA03 GPIO1_IO10 XBAR1_IN22 ENET_1588_EVENT0_OUT FLEXCAN3_TX ARM_TRACE_SWO - PA11 = portA + 11 // [AD_B0_11]: JTAG_TRSTB FLEXPWM1_PWMB03 ENET_COL WDOG1_WDOG_B CSI_DATA02 GPIO1_IO11 XBAR1_IN23 ENET_1588_EVENT0_IN FLEXCAN3_RX SEMC_CLK6 - PA12 = portA + 12 // [AD_B0_12]: LPI2C4_SCL CCM_PMIC_READY LPUART1_TX WDOG2_WDOG_B FLEXPWM1_PWMX02 GPIO1_IO12 ENET_1588_EVENT1_OUT NMI_GLUE_NMI ~ ~ - PA13 = portA + 13 // [AD_B0_13]: LPI2C4_SDA GPT1_CLK LPUART1_RX EWM_OUT_B FLEXPWM1_PWMX03 GPIO1_IO13 ENET_1588_EVENT1_IN REF_CLK_24M ~ ~ - PA14 = portA + 14 // [AD_B0_14]: USB_OTG2_OC XBAR1_IN24 LPUART1_CTS_B ENET_1588_EVENT0_OUT CSI_VSYNC GPIO1_IO14 FLEXCAN2_TX FLEXCAN3_TX ~ ~ - PA15 = portA + 15 // [AD_B0_15]: USB_OTG2_PWR XBAR1_IN25 LPUART1_RTS_B ENET_1588_EVENT0_IN CSI_HSYNC GPIO1_IO15 FLEXCAN2_RX WDOG1_WDOG_RST_B_DEB FLEXCAN3_RX ~ - PA16 = portA + 16 // [AD_B1_00]: USB_OTG2_ID QTIMER3_TIMER0 LPUART2_CTS_B LPI2C1_SCL WDOG1_B GPIO1_IO16 USDHC1_WP KPP_ROW07 ENET2_1588_EVENT0_OUT FLEXIO3_FLEXIO00 - PA17 = portA + 17 // [AD_B1_01]: USB_OTG1_PWR QTIMER3_TIMER1 LPUART2_RTS_B LPI2C1_SDA CCM_PMIC_READY GPIO1_IO17 USDHC1_VSELECT KPP_COL07 ENET2_1588_EVENT0_IN FLEXIO3_FLEXIO01 - PA18 = portA + 18 // [AD_B1_02]: USB_OTG1_ID QTIMER3_TIMER2 LPUART2_TX SPDIF_OUT ENET_1588_EVENT2_OUT GPIO1_IO18 USDHC1_CD_B KPP_ROW06 GPT2_CLK FLEXIO3_FLEXIO02 - PA19 = portA + 19 // [AD_B1_03]: USB_OTG1_OC QTIMER3_TIMER3 LPUART2_RX SPDIF_IN ENET_1588_EVENT2_IN GPIO1_IO19 USDHC2_CD_B KPP_COL06 GPT2_CAPTURE1 FLEXIO3_FLEXIO03 - PA20 = portA + 20 // [AD_B1_04]: FLEXSPIB_DATA03 ENET_MDC LPUART3_CTS_B SPDIF_SR_CLK CSI_PIXCLK GPIO1_IO20 USDHC2_DATA0 KPP_ROW05 GPT2_CAPTURE2 FLEXIO3_FLEXIO04 - PA21 = portA + 21 // [AD_B1_05]: FLEXSPIB_DATA02 ENET_MDIO LPUART3_RTS_B SPDIF_OUT CSI_MCLK GPIO1_IO21 USDHC2_DATA1 KPP_COL05 GPT2_COMPARE1 FLEXIO3_FLEXIO05 - PA22 = portA + 22 // [AD_B1_06]: FLEXSPIB_DATA01 LPI2C3_SDA LPUART3_TX SPDIF_LOCK CSI_VSYNC GPIO1_IO22 USDHC2_DATA2 KPP_ROW04 GPT2_COMPARE2 FLEXIO3_FLEXIO06 - PA23 = portA + 23 // [AD_B1_07]: FLEXSPIB_DATA00 LPI2C3_SCL LPUART3_RX SPDIF_EXT_CLK CSI_HSYNC GPIO1_IO23 USDHC2_DATA3 KPP_COL04 GPT2_COMPARE3 FLEXIO3_FLEXIO07 - PA24 = portA + 24 // [AD_B1_08]: FLEXSPIA_SS1_B FLEXPWM4_PWMA00 FLEXCAN1_TX CCM_PMIC_READY CSI_DATA09 GPIO1_IO24 USDHC2_CMD KPP_ROW03 FLEXIO3_FLEXIO08 ~ - PA25 = portA + 25 // [AD_B1_09]: FLEXSPIA_DQS FLEXPWM4_PWMA01 FLEXCAN1_RX SAI1_MCLK CSI_DATA08 GPIO1_IO25 USDHC2_CLK KPP_COL03 FLEXIO3_FLEXIO09 ~ - PA26 = portA + 26 // [AD_B1_10]: FLEXSPIA_DATA03 WDOG1_B LPUART8_TX SAI1_RX_SYNC CSI_DATA07 GPIO1_IO26 USDHC2_WP KPP_ROW02 ENET2_1588_EVENT1_OUT FLEXIO3_FLEXIO10 - PA27 = portA + 27 // [AD_B1_11]: FLEXSPIA_DATA02 EWM_OUT_B LPUART8_RX SAI1_RX_BCLK CSI_DATA06 GPIO1_IO27 USDHC2_RESET_B KPP_COL02 ENET2_1588_EVENT1_IN FLEXIO3_FLEXIO11 - PA28 = portA + 28 // [AD_B1_12]: FLEXSPIA_DATA01 ACMP_OUT00 LPSPI3_PCS0 SAI1_RX_DATA00 CSI_DATA05 GPIO1_IO28 USDHC2_DATA4 KPP_ROW01 ENET2_1588_EVENT2_OUT FLEXIO3_FLEXIO12 - PA29 = portA + 29 // [AD_B1_13]: FLEXSPIA_DATA00 ACMP_OUT01 LPSPI3_SDI SAI1_TX_DATA00 CSI_DATA04 GPIO1_IO29 USDHC2_DATA5 KPP_COL01 ENET2_1588_EVENT2_IN FLEXIO3_FLEXIO13 - PA30 = portA + 30 // [AD_B1_14]: FLEXSPIA_SCLK ACMP_OUT02 LPSPI3_SDO SAI1_TX_BCLK CSI_DATA03 GPIO1_IO30 USDHC2_DATA6 KPP_ROW00 ENET2_1588_EVENT3_OUT FLEXIO3_FLEXIO14 - PA31 = portA + 31 // [AD_B1_15]: FLEXSPIA_SS0_B ACMP_OUT03 LPSPI3_SCK SAI1_TX_SYNC CSI_DATA02 GPIO1_IO31 USDHC2_DATA7 KPP_COL00 ENET2_1588_EVENT3_IN FLEXIO3_FLEXIO15 - - PB0 = portB + 0 // [B0_00]: LCD_CLK QTIMER1_TIMER0 MQS_RIGHT LPSPI4_PCS0 FLEXIO2_FLEXIO00 GPIO2_IO00 SEMC_CSX01 ENET2_MDC ~ ~ - PB1 = portB + 1 // [B0_01]: LCD_ENABLE QTIMER1_TIMER1 MQS_LEFT LPSPI4_SDI FLEXIO2_FLEXIO01 GPIO2_IO01 SEMC_CSX02 ENET2_MDIO ~ ~ - PB2 = portB + 2 // [B0_02]: LCD_HSYNC QTIMER1_TIMER2 FLEXCAN1_TX LPSPI4_SDO FLEXIO2_FLEXIO02 GPIO2_IO02 SEMC_CSX03 ENET2_1588_EVENT0_OUT ~ ~ - PB3 = portB + 3 // [B0_03]: LCD_VSYNC QTIMER2_TIMER0 FLEXCAN1_RX LPSPI4_SCK FLEXIO2_FLEXIO03 GPIO2_IO03 WDOG2_RESET_B_DEB ENET2_1588_EVENT0_IN ~ ~ - PB4 = portB + 4 // [B0_04]: LCD_DATA00 QTIMER2_TIMER1 LPI2C2_SCL ARM_TRACE0 FLEXIO2_FLEXIO04 GPIO2_IO04 SRC_BOOT_CFG00 ENET2_TDATA03 ~ ~ - PB5 = portB + 5 // [B0_05]: LCD_DATA01 QTIMER2_TIMER2 LPI2C2_SDA ARM_TRACE1 FLEXIO2_FLEXIO05 GPIO2_IO05 SRC_BOOT_CFG01 ENET2_TDATA02 ~ ~ - PB6 = portB + 6 // [B0_06]: LCD_DATA02 QTIMER3_TIMER0 FLEXPWM2_PWMA00 ARM_TRACE2 FLEXIO2_FLEXIO06 GPIO2_IO06 SRC_BOOT_CFG02 ENET2_RX_CLK ~ ~ - PB7 = portB + 7 // [B0_07]: LCD_DATA03 QTIMER3_TIMER1 FLEXPWM2_PWMB00 ARM_TRACE3 FLEXIO2_FLEXIO07 GPIO2_IO07 SRC_BOOT_CFG03 ENET2_TX_ER ~ ~ - PB8 = portB + 8 // [B0_08]: LCD_DATA04 QTIMER3_TIMER2 FLEXPWM2_PWMA01 LPUART3_TX FLEXIO2_FLEXIO08 GPIO2_IO08 SRC_BOOT_CFG04 ENET2_RDATA03 ~ ~ - PB9 = portB + 9 // [B0_09]: LCD_DATA05 QTIMER4_TIMER0 FLEXPWM2_PWMB01 LPUART3_RX FLEXIO2_FLEXIO09 GPIO2_IO09 SRC_BOOT_CFG05 ENET2_RDATA02 ~ ~ - PB10 = portB + 10 // [B0_10]: LCD_DATA06 QTIMER4_TIMER1 FLEXPWM2_PWMA02 SAI1_TX_DATA03 FLEXIO2_FLEXIO10 GPIO2_IO10 SRC_BOOT_CFG06 ENET2_CRS ~ ~ - PB11 = portB + 11 // [B0_11]: LCD_DATA07 QTIMER4_TIMER2 FLEXPWM2_PWMB02 SAI1_TX_DATA02 FLEXIO2_FLEXIO11 GPIO2_IO11 SRC_BOOT_CFG07 ENET2_COL ~ ~ - PB12 = portB + 12 // [B0_12]: LCD_DATA08 XBAR1_INOUT10 ARM_TRACE_CLK SAI1_TX_DATA01 FLEXIO2_FLEXIO12 GPIO2_IO12 SRC_BOOT_CFG08 ENET2_TDATA00 ~ ~ - PB13 = portB + 13 // [B0_13]: LCD_DATA09 XBAR1_INOUT11 ARM_TRACE_SWO SAI1_MCLK FLEXIO2_FLEXIO13 GPIO2_IO13 SRC_BOOT_CFG09 ENET2_TDATA01 ~ ~ - PB14 = portB + 14 // [B0_14]: LCD_DATA10 XBAR1_INOUT12 ARM_TXEV SAI1_RX_SYNC FLEXIO2_FLEXIO14 GPIO2_IO14 SRC_BOOT_CFG10 ENET2_TX_EN ~ ~ - PB15 = portB + 15 // [B0_15]: LCD_DATA11 XBAR1_INOUT13 ARM_RXEV SAI1_RX_BCLK FLEXIO2_FLEXIO15 GPIO2_IO15 SRC_BOOT_CFG11 ENET2_TX_CLK ENET2_REF_CLK2 ~ - PB16 = portB + 16 // [B1_00]: LCD_DATA12 XBAR1_INOUT14 LPUART4_TX SAI1_RX_DATA00 FLEXIO2_FLEXIO16 GPIO2_IO16 FLEXPWM1_PWMA03 ENET2_RX_ER FLEXIO3_FLEXIO16 ~ - PB17 = portB + 17 // [B1_01]: LCD_DATA13 XBAR1_INOUT15 LPUART4_RX SAI1_TX_DATA00 FLEXIO2_FLEXIO17 GPIO2_IO17 FLEXPWM1_PWMB03 ENET2_RDATA00 FLEXIO3_FLEXIO17 ~ - PB18 = portB + 18 // [B1_02]: LCD_DATA14 XBAR1_INOUT16 LPSPI4_PCS2 SAI1_TX_BCLK FLEXIO2_FLEXIO18 GPIO2_IO18 FLEXPWM2_PWMA03 ENET2_RDATA01 FLEXIO3_FLEXIO18 ~ - PB19 = portB + 19 // [B1_03]: LCD_DATA15 XBAR1_INOUT17 LPSPI4_PCS1 SAI1_TX_SYNC FLEXIO2_FLEXIO19 GPIO2_IO19 FLEXPWM2_PWMB03 ENET2_RX_EN FLEXIO3_FLEXIO19 ~ - PB20 = portB + 20 // [B1_04]: LCD_DATA16 LPSPI4_PCS0 CSI_DATA15 ENET_RX_DATA00 FLEXIO2_FLEXIO20 GPIO2_IO20 GPT1_CLK FLEXIO3_FLEXIO20 ~ ~ - PB21 = portB + 21 // [B1_05]: LCD_DATA17 LPSPI4_SDI CSI_DATA14 ENET_RX_DATA01 FLEXIO2_FLEXIO21 GPIO2_IO21 GPT1_CAPTURE1 FLEXIO3_FLEXIO21 ~ ~ - PB22 = portB + 22 // [B1_06]: LCD_DATA18 LPSPI4_SDO CSI_DATA13 ENET_RX_EN FLEXIO2_FLEXIO22 GPIO2_IO22 GPT1_CAPTURE2 FLEXIO3_FLEXIO22 ~ ~ - PB23 = portB + 23 // [B1_07]: LCD_DATA19 LPSPI4_SCK CSI_DATA12 ENET_TX_DATA00 FLEXIO2_FLEXIO23 GPIO2_IO23 GPT1_COMPARE1 FLEXIO3_FLEXIO23 ~ ~ - PB24 = portB + 24 // [B1_08]: LCD_DATA20 QTIMER1_TIMER3 CSI_DATA11 ENET_TX_DATA01 FLEXIO2_FLEXIO24 GPIO2_IO24 FLEXCAN2_TX GPT1_COMPARE2 FLEXIO3_FLEXIO24 ~ - PB25 = portB + 25 // [B1_09]: LCD_DATA21 QTIMER2_TIMER3 CSI_DATA10 ENET_TX_EN FLEXIO2_FLEXIO25 GPIO2_IO25 FLEXCAN2_RX GPT1_COMPARE3 FLEXIO3_FLEXIO25 ~ - PB26 = portB + 26 // [B1_10]: LCD_DATA22 QTIMER3_TIMER3 CSI_DATA00 ENET_TX_CLK FLEXIO2_FLEXIO26 GPIO2_IO26 ENET_REF_CLK FLEXIO3_FLEXIO26 ~ ~ - PB27 = portB + 27 // [B1_11]: LCD_DATA23 QTIMER4_TIMER3 CSI_DATA01 ENET_RX_ER FLEXIO2_FLEXIO27 GPIO2_IO27 LPSPI4_PCS3 FLEXIO3_FLEXIO27 ~ ~ - PB28 = portB + 28 // [B1_12]: LPUART5_TX CSI_PIXCLK ENET_1588_EVENT0_IN FLEXIO2_FLEXIO28 GPIO2_IO28 USDHC1_CD_B FLEXIO3_FLEXIO28 ~ ~ ~ - PB29 = portB + 29 // [B1_13]: WDOG1_B LPUART5_RX CSI_VSYNC ENET_1588_EVENT0_OUT FLEXIO2_FLEXIO29 GPIO2_IO29 USDHC1_WP SEMC_DQS4 FLEXIO3_FLEXIO29 ~ - PB30 = portB + 30 // [B1_14]: ENET_MDC FLEXPWM4_PWMA02 CSI_HSYNC XBAR1_IN02 FLEXIO2_FLEXIO30 GPIO2_IO30 USDHC1_VSELECT ENET2_TDATA00 FLEXIO3_FLEXIO30 ~ - PB31 = portB + 31 // [B1_15]: ENET_MDIO FLEXPWM4_PWMA03 CSI_MCLK XBAR1_IN03 FLEXIO2_FLEXIO31 GPIO2_IO31 USDHC1_RESET_B ENET2_TDATA01 FLEXIO3_FLEXIO31 ~ - - PC0 = portC + 0 // [SD_B1_00]: USDHC2_DATA3 FLEXSPIB_DATA03 FLEXPWM1_PWMA03 SAI1_TX_DATA03 LPUART4_TX GPIO3_IO00 SAI3_RX_DATA ~ ~ ~ - PC1 = portC + 1 // [SD_B1_01]: USDHC2_DATA2 FLEXSPIB_DATA02 FLEXPWM1_PWMB03 SAI1_TX_DATA02 LPUART4_RX GPIO3_IO01 SAI3_TX_DATA ~ ~ ~ - PC2 = portC + 2 // [SD_B1_02]: USDHC2_DATA1 FLEXSPIB_DATA01 FLEXPWM2_PWMA03 SAI1_TX_DATA01 FLEXCAN1_TX GPIO3_IO02 CCM_WAIT SAI3_TX_SYNC ~ ~ - PC3 = portC + 3 // [SD_B1_03]: USDHC2_DATA0 FLEXSPIB_DATA00 FLEXPWM2_PWMB03 SAI1_MCLK FLEXCAN1_RX GPIO3_IO03 CCM_PMIC_READY SAI3_TX_BCLK ~ ~ - PC4 = portC + 4 // [SD_B1_04]: USDHC2_CLK FLEXSPIB_SCLK LPI2C1_SCL SAI1_RX_SYNC FLEXSPIA_SS1_B GPIO3_IO04 CCM_STOP SAI3_MCLK ~ ~ - PC5 = portC + 5 // [SD_B1_05]: USDHC2_CMD FLEXSPIA_DQS LPI2C1_SDA SAI1_RX_BCLK FLEXSPIB_SS0_B GPIO3_IO05 SAI3_RX_SYNC ~ ~ ~ - PC6 = portC + 6 // [SD_B1_06]: USDHC2_RESET_B FLEXSPIA_SS0_B LPUART7_CTS_B SAI1_RX_DATA00 LPSPI2_PCS0 GPIO3_IO06 SAI3_RX_BCLK ~ ~ ~ - PC7 = portC + 7 // [SD_B1_07]: SEMC_CSX01 FLEXSPIA_SCLK LPUART7_RTS_B SAI1_TX_DATA00 LPSPI2_SCK GPIO3_IO07 ~ ~ ~ ~ - PC8 = portC + 8 // [SD_B1_08]: USDHC2_DATA4 FLEXSPIA_DATA00 LPUART7_TX SAI1_TX_BCLK LPSPI2_SD0 GPIO3_IO08 SEMC_CSX02 ~ ~ ~ - PC9 = portC + 9 // [SD_B1_09]: USDHC2_DATA5 FLEXSPIA_DATA01 LPUART7_RX SAI1_TX_SYNC LPSPI2_SDI GPIO3_IO09 ~ ~ ~ ~ - PC10 = portC + 10 // [SD_B1_10]: USDHC2_DATA6 FLEXSPIA_DATA02 LPUART2_RX LPI2C2_SDA LPSPI2_PCS2 GPIO3_IO10 ~ ~ ~ ~ - PC11 = portC + 11 // [SD_B1_11]: USDHC2_DATA7 FLEXSPIA_DATA03 LPUART2_TX LPI2C2_SCL LPSPI2_PCS3 GPIO3_IO11 ~ ~ ~ ~ - PC12 = portC + 12 // [SD_B0_00]: USDHC1_CMD FLEXPWM1_PWMA00 LPI2C3_SCL XBAR1_INOUT04 LPSPI1_SCK GPIO3_IO12 FLEXSPIA_SS1_B ENET2_TX_EN SEMC_DQS4 ~ - PC13 = portC + 13 // [SD_B0_01]: USDHC1_CLK FLEXPWM1_PWMB00 LPI2C3_SDA XBAR1_INOUT05 LPSPI1_PCS0 GPIO3_IO13 FLEXSPIB_SS1_B ENET2_TX_CLK ENET2_REF_CLK2 ~ - PC14 = portC + 14 // [SD_B0_02]: USDHC1_DATA0 FLEXPWM1_PWMA01 LPUART8_CTS_B XBAR1_INOUT06 LPSPI1_SDO GPIO3_IO14 ENET2_RX_ER SEMC_CLK5 ~ ~ - PC15 = portC + 15 // [SD_B0_03]: USDHC1_DATA1 FLEXPWM1_PWMB01 LPUART8_RTS_B XBAR1_INOUT07 LPSPI1_SDI GPIO3_IO15 ENET2_RDATA00 SEMC_CLK6 ~ ~ - PC16 = portC + 16 // [SD_B0_04]: USDHC1_DATA2 FLEXPWM1_PWMA02 LPUART8_TX XBAR1_INOUT08 FLEXSPIB_SS0_B GPIO3_IO16 CCM_CLKO1 ENET2_RDATA01 ~ ~ - PC17 = portC + 17 // [SD_B0_05]: USDHC1_DATA3 FLEXPWM1_PWMB02 LPUART8_RX XBAR1_INOUT09 FLEXSPIB_DQS GPIO3_IO17 CCM_CLKO2 ENET2_RX_EN ~ ~ - PC18 = portC + 18 // [EMC_32]: SEMC_DATA10 FLEXPWM3_PWMB01 LPUART7_RX CCM_PMIC_RDY CSI_DATA21 GPIO3_IO18 ENET2_TX_EN ~ ~ ~ - PC19 = portC + 19 // [EMC_33]: SEMC_DATA11 FLEXPWM3_PWMA02 USDHC1_RESET_B SAI3_RX_DATA CSI_DATA20 GPIO3_IO19 ENET2_TX_CLK ENET2_REF_CLK2 ~ ~ - PC20 = portC + 20 // [EMC_34]: SEMC_DATA12 FLEXPWM3_PWMB02 USDHC1_VSELECT SAI3_RX_SYNC CSI_DATA19 GPIO3_IO20 ENET2_RX_ER ~ ~ ~ - PC21 = portC + 21 // [EMC_35]: SEMC_DATA13 XBAR1_INOUT18 GPT1_COMPARE1 SAI3_RX_BCLK CSI_DATA18 GPIO3_IO21 USDHC1_CD_B ENET2_RDATA00 ~ ~ - PC22 = portC + 22 // [EMC_36]: SEMC_DATA14 XBAR1_IN22 GPT1_COMPARE2 SAI3_TX_DATA CSI_DATA17 GPIO3_IO22 USDHC1_WP ENET2_RDATA01 FLEXCAN3_TX ~ - PC23 = portC + 23 // [EMC_37]: SEMC_DATA15 XBAR1_IN23 GPT1_COMPARE3 SAI3_MCLK CSI_DATA16 GPIO3_IO23 USDHC2_WP ENET2_RX_EN FLEXCAN3_RX ~ - PC24 = portC + 24 // [EMC_38]: SEMC_DM01 FLEXPWM1_PWMA03 LPUART8_TX SAI3_TX_BCLK CSI_FIELD GPIO3_IO24 USDHC2_VSELECT ENET2_MDC ~ ~ - PC25 = portC + 25 // [EMC_39]: SEMC_DQS FLEXPWM1_PWMB03 LPUART8_RX SAI3_TX_SYNC WDOG1_WDOG_B GPIO3_IO25 USDHC2_CD_B ENET2_MDIO SEMC_DQS4 ~ - PC26 = portC + 26 // [EMC_40]: SEMC_RDY GPT2_CAPTURE2 LPSPI1_PCS2 USB_OTG2_OC ENET_MDC GPIO3_IO26 USDHC2_RESET_B SEMC_CLK5 ~ ~ - PC27 = portC + 27 // [EMC_41]: SEMC_CSX00 GPT2_CAPTURE1 LPSPI1_PCS3 USB_OTG2_PWR ENET_MDIO GPIO3_IO27 USDHC1_VSELECT ~ ~ ~ - _ = portC + 28 // - _ = portC + 29 // - _ = portC + 30 // - _ = portC + 31 // - - PD0 = portD + 0 // [EMC_00]: SEMC_DATA00 FLEXPWM4_PWMA00 LPSPI2_SCK XBAR1_XBAR_IN02 FLEXIO1_FLEXIO00 GPIO4_IO00 ~ ~ ~ ~ - PD1 = portD + 1 // [EMC_01]: SEMC_DATA01 FLEXPWM4_PWMB00 LPSPI2_PCS0 XBAR1_IN03 FLEXIO1_FLEXIO01 GPIO4_IO01 ~ ~ ~ ~ - PD2 = portD + 2 // [EMC_02]: SEMC_DATA02 FLEXPWM4_PWMA01 LPSPI2_SDO XBAR1_INOUT04 FLEXIO1_FLEXIO02 GPIO4_IO02 ~ ~ ~ ~ - PD3 = portD + 3 // [EMC_03]: SEMC_DATA03 FLEXPWM4_PWMB01 LPSPI2_SDI XBAR1_INOUT05 FLEXIO1_FLEXIO03 GPIO4_IO03 ~ ~ ~ ~ - PD4 = portD + 4 // [EMC_04]: SEMC_DATA04 FLEXPWM4_PWMA02 SAI2_TX_DATA XBAR1_INOUT06 FLEXIO1_FLEXIO04 GPIO4_IO04 ~ ~ ~ ~ - PD5 = portD + 5 // [EMC_05]: SEMC_DATA05 FLEXPWM4_PWMB02 SAI2_TX_SYNC XBAR1_INOUT07 FLEXIO1_FLEXIO05 GPIO4_IO05 ~ ~ ~ ~ - PD6 = portD + 6 // [EMC_06]: SEMC_DATA06 FLEXPWM2_PWMA00 SAI2_TX_BCLK XBAR1_INOUT08 FLEXIO1_FLEXIO06 GPIO4_IO06 ~ ~ ~ ~ - PD7 = portD + 7 // [EMC_07]: SEMC_DATA07 FLEXPWM2_PWMB00 SAI2_MCLK XBAR1_INOUT09 FLEXIO1_FLEXIO07 GPIO4_IO07 ~ ~ ~ ~ - PD8 = portD + 8 // [EMC_08]: SEMC_DM00 FLEXPWM2_PWMA01 SAI2_RX_DATA XBAR1_INOUT17 FLEXIO1_FLEXIO08 GPIO4_IO08 ~ ~ ~ ~ - PD9 = portD + 9 // [EMC_09]: SEMC_ADDR00 FLEXPWM2_PWMB01 SAI2_RX_SYNC FLEXCAN2_TX FLEXIO1_FLEXIO09 GPIO4_IO09 FLEXSPI2_B_SS1_B ~ ~ ~ - PD10 = portD + 10 // [EMC_10]: SEMC_ADDR01 FLEXPWM2_PWMA02 SAI2_RX_BCLK FLEXCAN2_RX FLEXIO1_FLEXIO10 GPIO4_IO10 FLEXSPI2_B_SS0_B ~ ~ ~ - PD11 = portD + 11 // [EMC_11]: SEMC_ADDR02 FLEXPWM2_PWMB02 LPI2C4_SDA USDHC2_RESET_B FLEXIO1_FLEXIO11 GPIO4_IO11 FLEXSPI2_B_DQS ~ ~ ~ - PD12 = portD + 12 // [EMC_12]: SEMC_ADDR03 XBAR1_IN24 LPI2C4_SCL USDHC1_WP FLEXPWM1_PWMA03 GPIO4_IO12 FLEXSPI2_B_SCLK ~ ~ ~ - PD13 = portD + 13 // [EMC_13]: SEMC_ADDR04 XBAR1_IN25 LPUART3_TX MQS_RIGHT FLEXPWM1_PWMB03 GPIO4_IO13 FLEXSPI2_B_DATA00 ~ ~ ~ - PD14 = portD + 14 // [EMC_14]: SEMC_ADDR05 XBAR1_INOUT19 LPUART3_RX MQS_LEFT LPSPI2_PCS1 GPIO4_IO14 FLEXSPI2_B_DATA01 ~ ~ ~ - PD15 = portD + 15 // [EMC_15]: SEMC_ADDR06 XBAR1_IN20 LPUART3_CTS_B SPDIF_OUT QTIMER3_TIMER0 GPIO4_IO15 FLEXSPI2_B_DATA02 ~ ~ ~ - PD16 = portD + 16 // [EMC_16]: SEMC_ADDR07 XBAR1_IN21 LPUART3_RTS_B SPDIF_IN QTIMER3_TIMER1 GPIO4_IO16 FLEXSPI2_B_DATA03 ~ ~ ~ - PD17 = portD + 17 // [EMC_17]: SEMC_ADDR08 FLEXPWM4_PWMA03 LPUART4_CTS_B FLEXCAN1_TX QTIMER3_TIMER2 GPIO4_IO17 ~ ~ ~ ~ - PD18 = portD + 18 // [EMC_18]: SEMC_ADDR09 FLEXPWM4_PWMB03 LPUART4_RTS_B FLEXCAN1_RX QTIMER3_TIMER3 GPIO4_IO18 SNVS_VIO_5_CTL ~ ~ ~ - PD19 = portD + 19 // [EMC_19]: SEMC_ADDR11 FLEXPWM2_PWMA03 LPUART4_TX ENET_RDATA01 QTIMER2_TIMER0 GPIO4_IO19 SNVS_VIO_5 ~ ~ ~ - PD20 = portD + 20 // [EMC_20]: SEMC_ADDR12 FLEXPWM2_PWMB03 LPUART4_RX ENET_RDATA00 QTIMER2_TIMER1 GPIO4_IO20 ~ ~ ~ ~ - PD21 = portD + 21 // [EMC_21]: SEMC_BA0 FLEXPWM3_PWMA03 LPI2C3_SDA ENET_TDATA01 QTIMER2_TIMER2 GPIO4_IO21 ~ ~ ~ ~ - PD22 = portD + 22 // [EMC_22]: SEMC_BA1 FLEXPWM3_PWMB03 LPI2C3_SCL ENET_TDATA00 QTIMER2_TIMER3 GPIO4_IO22 FLEXSPI2_A_SS1_B ~ ~ ~ - PD23 = portD + 23 // [EMC_23]: SEMC_ADDR10 FLEXPWM1_PWMA00 LPUART5_TX ENET_RX_EN GPT1_CAPTURE2 GPIO4_IO23 FLEXSPI2_A_DQS ~ ~ ~ - PD24 = portD + 24 // [EMC_24]: SEMC_CAS FLEXPWM1_PWMB00 LPUART5_RX ENET_TX_EN GPT1_CAPTURE1 GPIO4_IO24 FLEXSPI2_A_SS0_B ~ ~ ~ - PD25 = portD + 25 // [EMC_25]: SEMC_RAS FLEXPWM1_PWMA01 LPUART6_TX ENET_TX_CLK ENET_REF_CLK GPIO4_IO25 FLEXSPI2_A_SCLK ~ ~ ~ - PD26 = portD + 26 // [EMC_26]: SEMC_CLK FLEXPWM1_PWMB01 LPUART6_RX ENET_RX_ER FLEXIO1_FLEXIO12 GPIO4_IO26 FLEXSPI2_A_DATA00 ~ ~ ~ - PD27 = portD + 27 // [EMC_27]: SEMC_CKE FLEXPWM1_PWMA02 LPUART5_RTS_B LPSPI1_SCK FLEXIO1_FLEXIO13 GPIO4_IO27 FLEXSPI2_A_DATA01 ~ ~ ~ - PD28 = portD + 28 // [EMC_28]: SEMC_WE FLEXPWM1_PWMB02 LPUART5_CTS_B LPSPI1_SDO FLEXIO1_FLEXIO14 GPIO4_IO28 FLEXSPI2_A_DATA02 ~ ~ ~ - PD29 = portD + 29 // [EMC_29]: SEMC_CS0 FLEXPWM3_PWMA00 LPUART6_RTS_B LPSPI1_SDI FLEXIO1_FLEXIO15 GPIO4_IO29 FLEXSPI2_A_DATA03 ~ ~ ~ - PD30 = portD + 30 // [EMC_30]: SEMC_DATA08 FLEXPWM3_PWMB00 LPUART6_CTS_B LPSPI1_PCS0 CSI_DATA23 GPIO4_IO30 ENET2_TDATA00 ~ ~ ~ - PD31 = portD + 31 // [EMC_31]: SEMC_DATA09 FLEXPWM3_PWMA01 LPUART7_TX LPSPI1_PCS1 CSI_DATA22 GPIO4_IO31 ENET2_TDATA01 ~ ~ ~ -) - -func (p Pin) getPos() uint8 { return uint8(p % 32) } -func (p Pin) getMask() uint32 { return uint32(1) << p.getPos() } -func (p Pin) getPort() Pin { return Pin(p/32) * 32 } - -// Configure sets the GPIO pad and pin properties, and selects the appropriate -// alternate function, for a given Pin and PinConfig. -func (p Pin) Configure(config PinConfig) { - var ( - sre = uint32(0x01 << 0) - dse = func(n uint32) uint32 { return (n & 0x07) << 3 } - spd = func(n uint32) uint32 { return (n & 0x03) << 6 } - ode = uint32(0x01 << 11) - pke = uint32(0x01 << 12) - pue = uint32(0x01 << 13) - pup = func(n uint32) uint32 { return (n & 0x03) << 14 } - hys = uint32(0x01 << 16) - ) - - _, gpio := p.getGPIO() // use fast GPIO for all pins - pad, mux := p.getPad() - - // first configure the pad characteristics - switch config.Mode { - case PinInput: - gpio.GDIR.ClearBits(p.getMask()) - pad.Set(dse(7)) - - case PinInputPullup: - gpio.GDIR.ClearBits(p.getMask()) - pad.Set(dse(7) | pke | pue | pup(3) | hys) - - case PinInputPulldown: - gpio.GDIR.ClearBits(p.getMask()) - pad.Set(dse(7) | pke | pue | hys) - - case PinOutput: - gpio.GDIR.SetBits(p.getMask()) - pad.Set(dse(7)) - - case PinOutputOpenDrain: - gpio.GDIR.SetBits(p.getMask()) - pad.Set(dse(7) | ode) - - case PinDisable: - gpio.GDIR.ClearBits(p.getMask()) - pad.Set(dse(7) | hys) - - case PinInputAnalog: - gpio.GDIR.ClearBits(p.getMask()) - pad.Set(dse(7)) - - case PinModeUARTTX: - pad.Set(sre | dse(3) | spd(3)) - - case PinModeUARTRX: - pad.Set(dse(7) | pke | pue | pup(3) | hys) - - case PinModeSPISDI: - pad.Set(dse(7) | spd(2)) - - case PinModeSPISDO: - pad.Set(dse(7) | spd(2)) - - case PinModeSPICLK: - pad.Set(dse(7) | spd(2)) - - case PinModeSPICS: - pad.Set(dse(7)) - - case PinModeI2CSDA, PinModeI2CSCL: - pad.Set(ode | sre | dse(4) | spd(1) | pke | pue | pup(3)) - } - - // then configure the alternate function mux - mux.Set(p.getMuxMode(config)) -} - -// Get returns the current value of a GPIO pin. -func (p Pin) Get() bool { - _, gpio := p.getGPIO() // use fast GPIO for all pins - return gpio.PSR.HasBits(p.getMask()) -} - -// Set changes the value of the GPIO pin. The pin must be configured as output. -func (p Pin) Set(value bool) { - _, gpio := p.getGPIO() // use fast GPIO for all pins - if value { - gpio.DR_SET.Set(p.getMask()) - } else { - gpio.DR_CLEAR.Set(p.getMask()) - } -} - -// Toggle switches an output pin from low to high or from high to low. -func (p Pin) Toggle() { - _, gpio := p.getGPIO() // use fast GPIO for all pins - gpio.DR_TOGGLE.Set(p.getMask()) -} - -// dispatchInterrupt invokes the user-provided callback functions for external -// interrupts generated on the high-speed GPIO pins. -// -// Unfortunately, all four high-speed GPIO ports (A-D) are connected to just a -// single interrupt control line. Therefore, the interrupt status register (ISR) -// must be checked in all four GPIO ports on every interrupt. -func (jt *pinJumpTable) dispatchInterrupt(interrupt.Interrupt) { - handle := func(gpio *nxp.GPIO_Type, port Pin) { - if status := gpio.ISR.Get() & gpio.IMR.Get(); status != 0 { - gpio.ISR.Set(status) // clear interrupt - for status != 0 { - off := Pin(bits.TrailingZeros32(status)) // ctz - pin := Pin(port + off) - jt.lut[pin](pin) - status &^= 1 << off - } - } - } - if jt.numDefined > 0 { - handle(nxp.GPIO6, portA) - handle(nxp.GPIO7, portB) - handle(nxp.GPIO8, portC) - handle(nxp.GPIO9, portD) - } -} - -// set associates a function with a given Pin in the receiver lookup table. If -// the function is nil, the given Pin's associated function is removed. -func (jt *pinJumpTable) set(pin Pin, fn func(Pin)) { - if int(pin) < len(jt.lut) { - if nil != fn { - if nil == jt.lut[pin] { - jt.numDefined++ - } - jt.lut[pin] = fn - } else { - if nil != jt.lut[pin] { - jt.numDefined-- - } - jt.lut[pin] = nil - } - } -} - -// SetInterrupt sets an interrupt to be executed when a particular pin changes -// state. The pin should already be configured as an input, including a pull up -// or down if no external pull is provided. -// -// This call will replace a previously set callback on this pin. You can pass a -// nil func to unset the pin change interrupt. If you do so, the change -// parameter is ignored and can be set to any value (such as 0). -func (p Pin) SetInterrupt(change PinChange, callback func(Pin)) error { - _, gpio := p.getGPIO() // use fast GPIO for all pins - mask := p.getMask() - if nil != callback { - switch change { - case PinRising, PinFalling: - gpio.EDGE_SEL.ClearBits(mask) - var reg *volatile.Register32 - var pos uint8 - if pos = p.getPos(); pos < 16 { - reg = &gpio.ICR1 // ICR1 = pins 0-15 - } else { - reg = &gpio.ICR2 // ICR2 = pins 16-31 - pos -= 16 - } - reg.ReplaceBits(uint32(change), 0x3, pos*2) - case PinToggle: - gpio.EDGE_SEL.SetBits(mask) - } - pinISR.set(p, callback) // associate the callback with the pin - gpio.ISR.Set(mask) // clear any pending interrupt (W1C) - gpio.IMR.SetBits(mask) // enable external interrupt - } else { - pinISR.set(p, nil) // remove any associated callback from the pin - gpio.ISR.Set(mask) // clear any pending interrupt (W1C) - gpio.IMR.ClearBits(mask) // disable external interrupt - } - // enable or disable the interrupt based on number of defined callbacks - if pinISR.numDefined > 0 { - if nil == pinInterrupt { - // create the Interrupt if it is not yet defined - irq := interrupt.New(nxp.IRQ_GPIO6_7_8_9, pinISR.dispatchInterrupt) - pinInterrupt = &irq - pinInterrupt.Enable() - } - } else { - if nil != pinInterrupt { - // disable the interrupt if it is defined - pinInterrupt.Disable() - } - } - return nil -} - -// getGPIO returns both the normal (IPG_CLK_ROOT) and high-speed (AHB_CLK_ROOT) -// GPIO peripherals to which a given Pin is connected. -// -// Note that, currently, the device is configured to use high-speed GPIO for all -// pins (GPIO6-9), so the first return value should not be used (GPIO1-4). -// See the remarks and documentation reference in the comments preceding the -// const Pin definitions above. -func (p Pin) getGPIO() (norm *nxp.GPIO_Type, fast *nxp.GPIO_Type) { - switch p.getPort() { - case portA: - return nxp.GPIO1, nxp.GPIO6 - case portB: - return nxp.GPIO2, nxp.GPIO7 - case portC: - return nxp.GPIO3, nxp.GPIO8 - case portD: - return nxp.GPIO4, nxp.GPIO9 - default: - panic("machine: unknown port") - } -} - -// getPad returns both the pad and mux configuration registers for a given Pin. -func (p Pin) getPad() (pad *volatile.Register32, mux *volatile.Register32) { - switch p.getPort() { - case portA: - switch p.getPos() { - case 0: - return &nxp.IOMUXC.SW_PAD_CTL_PAD_GPIO_AD_B0_00, &nxp.IOMUXC.SW_MUX_CTL_PAD_GPIO_AD_B0_00 - case 1: - return &nxp.IOMUXC.SW_PAD_CTL_PAD_GPIO_AD_B0_01, &nxp.IOMUXC.SW_MUX_CTL_PAD_GPIO_AD_B0_01 - case 2: - return &nxp.IOMUXC.SW_PAD_CTL_PAD_GPIO_AD_B0_02, &nxp.IOMUXC.SW_MUX_CTL_PAD_GPIO_AD_B0_02 - case 3: - return &nxp.IOMUXC.SW_PAD_CTL_PAD_GPIO_AD_B0_03, &nxp.IOMUXC.SW_MUX_CTL_PAD_GPIO_AD_B0_03 - case 4: - return &nxp.IOMUXC.SW_PAD_CTL_PAD_GPIO_AD_B0_04, &nxp.IOMUXC.SW_MUX_CTL_PAD_GPIO_AD_B0_04 - case 5: - return &nxp.IOMUXC.SW_PAD_CTL_PAD_GPIO_AD_B0_05, &nxp.IOMUXC.SW_MUX_CTL_PAD_GPIO_AD_B0_05 - case 6: - return &nxp.IOMUXC.SW_PAD_CTL_PAD_GPIO_AD_B0_06, &nxp.IOMUXC.SW_MUX_CTL_PAD_GPIO_AD_B0_06 - case 7: - return &nxp.IOMUXC.SW_PAD_CTL_PAD_GPIO_AD_B0_07, &nxp.IOMUXC.SW_MUX_CTL_PAD_GPIO_AD_B0_07 - case 8: - return &nxp.IOMUXC.SW_PAD_CTL_PAD_GPIO_AD_B0_08, &nxp.IOMUXC.SW_MUX_CTL_PAD_GPIO_AD_B0_08 - case 9: - return &nxp.IOMUXC.SW_PAD_CTL_PAD_GPIO_AD_B0_09, &nxp.IOMUXC.SW_MUX_CTL_PAD_GPIO_AD_B0_09 - case 10: - return &nxp.IOMUXC.SW_PAD_CTL_PAD_GPIO_AD_B0_10, &nxp.IOMUXC.SW_MUX_CTL_PAD_GPIO_AD_B0_10 - case 11: - return &nxp.IOMUXC.SW_PAD_CTL_PAD_GPIO_AD_B0_11, &nxp.IOMUXC.SW_MUX_CTL_PAD_GPIO_AD_B0_11 - case 12: - return &nxp.IOMUXC.SW_PAD_CTL_PAD_GPIO_AD_B0_12, &nxp.IOMUXC.SW_MUX_CTL_PAD_GPIO_AD_B0_12 - case 13: - return &nxp.IOMUXC.SW_PAD_CTL_PAD_GPIO_AD_B0_13, &nxp.IOMUXC.SW_MUX_CTL_PAD_GPIO_AD_B0_13 - case 14: - return &nxp.IOMUXC.SW_PAD_CTL_PAD_GPIO_AD_B0_14, &nxp.IOMUXC.SW_MUX_CTL_PAD_GPIO_AD_B0_14 - case 15: - return &nxp.IOMUXC.SW_PAD_CTL_PAD_GPIO_AD_B0_15, &nxp.IOMUXC.SW_MUX_CTL_PAD_GPIO_AD_B0_15 - case 16: - return &nxp.IOMUXC.SW_PAD_CTL_PAD_GPIO_AD_B1_00, &nxp.IOMUXC.SW_MUX_CTL_PAD_GPIO_AD_B1_00 - case 17: - return &nxp.IOMUXC.SW_PAD_CTL_PAD_GPIO_AD_B1_01, &nxp.IOMUXC.SW_MUX_CTL_PAD_GPIO_AD_B1_01 - case 18: - return &nxp.IOMUXC.SW_PAD_CTL_PAD_GPIO_AD_B1_02, &nxp.IOMUXC.SW_MUX_CTL_PAD_GPIO_AD_B1_02 - case 19: - return &nxp.IOMUXC.SW_PAD_CTL_PAD_GPIO_AD_B1_03, &nxp.IOMUXC.SW_MUX_CTL_PAD_GPIO_AD_B1_03 - case 20: - return &nxp.IOMUXC.SW_PAD_CTL_PAD_GPIO_AD_B1_04, &nxp.IOMUXC.SW_MUX_CTL_PAD_GPIO_AD_B1_04 - case 21: - return &nxp.IOMUXC.SW_PAD_CTL_PAD_GPIO_AD_B1_05, &nxp.IOMUXC.SW_MUX_CTL_PAD_GPIO_AD_B1_05 - case 22: - return &nxp.IOMUXC.SW_PAD_CTL_PAD_GPIO_AD_B1_06, &nxp.IOMUXC.SW_MUX_CTL_PAD_GPIO_AD_B1_06 - case 23: - return &nxp.IOMUXC.SW_PAD_CTL_PAD_GPIO_AD_B1_07, &nxp.IOMUXC.SW_MUX_CTL_PAD_GPIO_AD_B1_07 - case 24: - return &nxp.IOMUXC.SW_PAD_CTL_PAD_GPIO_AD_B1_08, &nxp.IOMUXC.SW_MUX_CTL_PAD_GPIO_AD_B1_08 - case 25: - return &nxp.IOMUXC.SW_PAD_CTL_PAD_GPIO_AD_B1_09, &nxp.IOMUXC.SW_MUX_CTL_PAD_GPIO_AD_B1_09 - case 26: - return &nxp.IOMUXC.SW_PAD_CTL_PAD_GPIO_AD_B1_10, &nxp.IOMUXC.SW_MUX_CTL_PAD_GPIO_AD_B1_10 - case 27: - return &nxp.IOMUXC.SW_PAD_CTL_PAD_GPIO_AD_B1_11, &nxp.IOMUXC.SW_MUX_CTL_PAD_GPIO_AD_B1_11 - case 28: - return &nxp.IOMUXC.SW_PAD_CTL_PAD_GPIO_AD_B1_12, &nxp.IOMUXC.SW_MUX_CTL_PAD_GPIO_AD_B1_12 - case 29: - return &nxp.IOMUXC.SW_PAD_CTL_PAD_GPIO_AD_B1_13, &nxp.IOMUXC.SW_MUX_CTL_PAD_GPIO_AD_B1_13 - case 30: - return &nxp.IOMUXC.SW_PAD_CTL_PAD_GPIO_AD_B1_14, &nxp.IOMUXC.SW_MUX_CTL_PAD_GPIO_AD_B1_14 - case 31: - return &nxp.IOMUXC.SW_PAD_CTL_PAD_GPIO_AD_B1_15, &nxp.IOMUXC.SW_MUX_CTL_PAD_GPIO_AD_B1_15 - } - case portB: - switch p.getPos() { - case 0: - return &nxp.IOMUXC.SW_PAD_CTL_PAD_GPIO_B0_00, &nxp.IOMUXC.SW_MUX_CTL_PAD_GPIO_B0_00 - case 1: - return &nxp.IOMUXC.SW_PAD_CTL_PAD_GPIO_B0_01, &nxp.IOMUXC.SW_MUX_CTL_PAD_GPIO_B0_01 - case 2: - return &nxp.IOMUXC.SW_PAD_CTL_PAD_GPIO_B0_02, &nxp.IOMUXC.SW_MUX_CTL_PAD_GPIO_B0_02 - case 3: - return &nxp.IOMUXC.SW_PAD_CTL_PAD_GPIO_B0_03, &nxp.IOMUXC.SW_MUX_CTL_PAD_GPIO_B0_03 - case 4: - return &nxp.IOMUXC.SW_PAD_CTL_PAD_GPIO_B0_04, &nxp.IOMUXC.SW_MUX_CTL_PAD_GPIO_B0_04 - case 5: - return &nxp.IOMUXC.SW_PAD_CTL_PAD_GPIO_B0_05, &nxp.IOMUXC.SW_MUX_CTL_PAD_GPIO_B0_05 - case 6: - return &nxp.IOMUXC.SW_PAD_CTL_PAD_GPIO_B0_06, &nxp.IOMUXC.SW_MUX_CTL_PAD_GPIO_B0_06 - case 7: - return &nxp.IOMUXC.SW_PAD_CTL_PAD_GPIO_B0_07, &nxp.IOMUXC.SW_MUX_CTL_PAD_GPIO_B0_07 - case 8: - return &nxp.IOMUXC.SW_PAD_CTL_PAD_GPIO_B0_08, &nxp.IOMUXC.SW_MUX_CTL_PAD_GPIO_B0_08 - case 9: - return &nxp.IOMUXC.SW_PAD_CTL_PAD_GPIO_B0_09, &nxp.IOMUXC.SW_MUX_CTL_PAD_GPIO_B0_09 - case 10: - return &nxp.IOMUXC.SW_PAD_CTL_PAD_GPIO_B0_10, &nxp.IOMUXC.SW_MUX_CTL_PAD_GPIO_B0_10 - case 11: - return &nxp.IOMUXC.SW_PAD_CTL_PAD_GPIO_B0_11, &nxp.IOMUXC.SW_MUX_CTL_PAD_GPIO_B0_11 - case 12: - return &nxp.IOMUXC.SW_PAD_CTL_PAD_GPIO_B0_12, &nxp.IOMUXC.SW_MUX_CTL_PAD_GPIO_B0_12 - case 13: - return &nxp.IOMUXC.SW_PAD_CTL_PAD_GPIO_B0_13, &nxp.IOMUXC.SW_MUX_CTL_PAD_GPIO_B0_13 - case 14: - return &nxp.IOMUXC.SW_PAD_CTL_PAD_GPIO_B0_14, &nxp.IOMUXC.SW_MUX_CTL_PAD_GPIO_B0_14 - case 15: - return &nxp.IOMUXC.SW_PAD_CTL_PAD_GPIO_B0_15, &nxp.IOMUXC.SW_MUX_CTL_PAD_GPIO_B0_15 - case 16: - return &nxp.IOMUXC.SW_PAD_CTL_PAD_GPIO_B1_00, &nxp.IOMUXC.SW_MUX_CTL_PAD_GPIO_B1_00 - case 17: - return &nxp.IOMUXC.SW_PAD_CTL_PAD_GPIO_B1_01, &nxp.IOMUXC.SW_MUX_CTL_PAD_GPIO_B1_01 - case 18: - return &nxp.IOMUXC.SW_PAD_CTL_PAD_GPIO_B1_02, &nxp.IOMUXC.SW_MUX_CTL_PAD_GPIO_B1_02 - case 19: - return &nxp.IOMUXC.SW_PAD_CTL_PAD_GPIO_B1_03, &nxp.IOMUXC.SW_MUX_CTL_PAD_GPIO_B1_03 - case 20: - return &nxp.IOMUXC.SW_PAD_CTL_PAD_GPIO_B1_04, &nxp.IOMUXC.SW_MUX_CTL_PAD_GPIO_B1_04 - case 21: - return &nxp.IOMUXC.SW_PAD_CTL_PAD_GPIO_B1_05, &nxp.IOMUXC.SW_MUX_CTL_PAD_GPIO_B1_05 - case 22: - return &nxp.IOMUXC.SW_PAD_CTL_PAD_GPIO_B1_06, &nxp.IOMUXC.SW_MUX_CTL_PAD_GPIO_B1_06 - case 23: - return &nxp.IOMUXC.SW_PAD_CTL_PAD_GPIO_B1_07, &nxp.IOMUXC.SW_MUX_CTL_PAD_GPIO_B1_07 - case 24: - return &nxp.IOMUXC.SW_PAD_CTL_PAD_GPIO_B1_08, &nxp.IOMUXC.SW_MUX_CTL_PAD_GPIO_B1_08 - case 25: - return &nxp.IOMUXC.SW_PAD_CTL_PAD_GPIO_B1_09, &nxp.IOMUXC.SW_MUX_CTL_PAD_GPIO_B1_09 - case 26: - return &nxp.IOMUXC.SW_PAD_CTL_PAD_GPIO_B1_10, &nxp.IOMUXC.SW_MUX_CTL_PAD_GPIO_B1_10 - case 27: - return &nxp.IOMUXC.SW_PAD_CTL_PAD_GPIO_B1_11, &nxp.IOMUXC.SW_MUX_CTL_PAD_GPIO_B1_11 - case 28: - return &nxp.IOMUXC.SW_PAD_CTL_PAD_GPIO_B1_12, &nxp.IOMUXC.SW_MUX_CTL_PAD_GPIO_B1_12 - case 29: - return &nxp.IOMUXC.SW_PAD_CTL_PAD_GPIO_B1_13, &nxp.IOMUXC.SW_MUX_CTL_PAD_GPIO_B1_13 - case 30: - return &nxp.IOMUXC.SW_PAD_CTL_PAD_GPIO_B1_14, &nxp.IOMUXC.SW_MUX_CTL_PAD_GPIO_B1_14 - case 31: - return &nxp.IOMUXC.SW_PAD_CTL_PAD_GPIO_B1_15, &nxp.IOMUXC.SW_MUX_CTL_PAD_GPIO_B1_15 - } - case portC: - switch p.getPos() { - case 0: - return &nxp.IOMUXC.SW_PAD_CTL_PAD_GPIO_SD_B1_00, &nxp.IOMUXC.SW_MUX_CTL_PAD_GPIO_SD_B1_00 - case 1: - return &nxp.IOMUXC.SW_PAD_CTL_PAD_GPIO_SD_B1_01, &nxp.IOMUXC.SW_MUX_CTL_PAD_GPIO_SD_B1_01 - case 2: - return &nxp.IOMUXC.SW_PAD_CTL_PAD_GPIO_SD_B1_02, &nxp.IOMUXC.SW_MUX_CTL_PAD_GPIO_SD_B1_02 - case 3: - return &nxp.IOMUXC.SW_PAD_CTL_PAD_GPIO_SD_B1_03, &nxp.IOMUXC.SW_MUX_CTL_PAD_GPIO_SD_B1_03 - case 4: - return &nxp.IOMUXC.SW_PAD_CTL_PAD_GPIO_SD_B1_04, &nxp.IOMUXC.SW_MUX_CTL_PAD_GPIO_SD_B1_04 - case 5: - return &nxp.IOMUXC.SW_PAD_CTL_PAD_GPIO_SD_B1_05, &nxp.IOMUXC.SW_MUX_CTL_PAD_GPIO_SD_B1_05 - case 6: - return &nxp.IOMUXC.SW_PAD_CTL_PAD_GPIO_SD_B1_06, &nxp.IOMUXC.SW_MUX_CTL_PAD_GPIO_SD_B1_06 - case 7: - return &nxp.IOMUXC.SW_PAD_CTL_PAD_GPIO_SD_B1_07, &nxp.IOMUXC.SW_MUX_CTL_PAD_GPIO_SD_B1_07 - case 8: - return &nxp.IOMUXC.SW_PAD_CTL_PAD_GPIO_SD_B1_08, &nxp.IOMUXC.SW_MUX_CTL_PAD_GPIO_SD_B1_08 - case 9: - return &nxp.IOMUXC.SW_PAD_CTL_PAD_GPIO_SD_B1_09, &nxp.IOMUXC.SW_MUX_CTL_PAD_GPIO_SD_B1_09 - case 10: - return &nxp.IOMUXC.SW_PAD_CTL_PAD_GPIO_SD_B1_10, &nxp.IOMUXC.SW_MUX_CTL_PAD_GPIO_SD_B1_10 - case 11: - return &nxp.IOMUXC.SW_PAD_CTL_PAD_GPIO_SD_B1_11, &nxp.IOMUXC.SW_MUX_CTL_PAD_GPIO_SD_B1_11 - case 12: - return &nxp.IOMUXC.SW_PAD_CTL_PAD_GPIO_SD_B0_00, &nxp.IOMUXC.SW_MUX_CTL_PAD_GPIO_SD_B0_00 - case 13: - return &nxp.IOMUXC.SW_PAD_CTL_PAD_GPIO_SD_B0_01, &nxp.IOMUXC.SW_MUX_CTL_PAD_GPIO_SD_B0_01 - case 14: - return &nxp.IOMUXC.SW_PAD_CTL_PAD_GPIO_SD_B0_02, &nxp.IOMUXC.SW_MUX_CTL_PAD_GPIO_SD_B0_02 - case 15: - return &nxp.IOMUXC.SW_PAD_CTL_PAD_GPIO_SD_B0_03, &nxp.IOMUXC.SW_MUX_CTL_PAD_GPIO_SD_B0_03 - case 16: - return &nxp.IOMUXC.SW_PAD_CTL_PAD_GPIO_SD_B0_04, &nxp.IOMUXC.SW_MUX_CTL_PAD_GPIO_SD_B0_04 - case 17: - return &nxp.IOMUXC.SW_PAD_CTL_PAD_GPIO_SD_B0_05, &nxp.IOMUXC.SW_MUX_CTL_PAD_GPIO_SD_B0_05 - case 18: - return &nxp.IOMUXC.SW_PAD_CTL_PAD_GPIO_EMC_32, &nxp.IOMUXC.SW_MUX_CTL_PAD_GPIO_EMC_32 - case 19: - return &nxp.IOMUXC.SW_PAD_CTL_PAD_GPIO_EMC_33, &nxp.IOMUXC.SW_MUX_CTL_PAD_GPIO_EMC_33 - case 20: - return &nxp.IOMUXC.SW_PAD_CTL_PAD_GPIO_EMC_34, &nxp.IOMUXC.SW_MUX_CTL_PAD_GPIO_EMC_34 - case 21: - return &nxp.IOMUXC.SW_PAD_CTL_PAD_GPIO_EMC_35, &nxp.IOMUXC.SW_MUX_CTL_PAD_GPIO_EMC_35 - case 22: - return &nxp.IOMUXC.SW_PAD_CTL_PAD_GPIO_EMC_36, &nxp.IOMUXC.SW_MUX_CTL_PAD_GPIO_EMC_36 - case 23: - return &nxp.IOMUXC.SW_PAD_CTL_PAD_GPIO_EMC_37, &nxp.IOMUXC.SW_MUX_CTL_PAD_GPIO_EMC_37 - case 24: - return &nxp.IOMUXC.SW_PAD_CTL_PAD_GPIO_EMC_38, &nxp.IOMUXC.SW_MUX_CTL_PAD_GPIO_EMC_38 - case 25: - return &nxp.IOMUXC.SW_PAD_CTL_PAD_GPIO_EMC_39, &nxp.IOMUXC.SW_MUX_CTL_PAD_GPIO_EMC_39 - case 26: - return &nxp.IOMUXC.SW_PAD_CTL_PAD_GPIO_EMC_40, &nxp.IOMUXC.SW_MUX_CTL_PAD_GPIO_EMC_40 - case 27: - return &nxp.IOMUXC.SW_PAD_CTL_PAD_GPIO_EMC_41, &nxp.IOMUXC.SW_MUX_CTL_PAD_GPIO_EMC_41 - case 28, 29, 30, 31: - } - case portD: - switch p.getPos() { - case 0: - return &nxp.IOMUXC.SW_PAD_CTL_PAD_GPIO_EMC_00, &nxp.IOMUXC.SW_MUX_CTL_PAD_GPIO_EMC_00 - case 1: - return &nxp.IOMUXC.SW_PAD_CTL_PAD_GPIO_EMC_01, &nxp.IOMUXC.SW_MUX_CTL_PAD_GPIO_EMC_01 - case 2: - return &nxp.IOMUXC.SW_PAD_CTL_PAD_GPIO_EMC_02, &nxp.IOMUXC.SW_MUX_CTL_PAD_GPIO_EMC_02 - case 3: - return &nxp.IOMUXC.SW_PAD_CTL_PAD_GPIO_EMC_03, &nxp.IOMUXC.SW_MUX_CTL_PAD_GPIO_EMC_03 - case 4: - return &nxp.IOMUXC.SW_PAD_CTL_PAD_GPIO_EMC_04, &nxp.IOMUXC.SW_MUX_CTL_PAD_GPIO_EMC_04 - case 5: - return &nxp.IOMUXC.SW_PAD_CTL_PAD_GPIO_EMC_05, &nxp.IOMUXC.SW_MUX_CTL_PAD_GPIO_EMC_05 - case 6: - return &nxp.IOMUXC.SW_PAD_CTL_PAD_GPIO_EMC_06, &nxp.IOMUXC.SW_MUX_CTL_PAD_GPIO_EMC_06 - case 7: - return &nxp.IOMUXC.SW_PAD_CTL_PAD_GPIO_EMC_07, &nxp.IOMUXC.SW_MUX_CTL_PAD_GPIO_EMC_07 - case 8: - return &nxp.IOMUXC.SW_PAD_CTL_PAD_GPIO_EMC_08, &nxp.IOMUXC.SW_MUX_CTL_PAD_GPIO_EMC_08 - case 9: - return &nxp.IOMUXC.SW_PAD_CTL_PAD_GPIO_EMC_09, &nxp.IOMUXC.SW_MUX_CTL_PAD_GPIO_EMC_09 - case 10: - return &nxp.IOMUXC.SW_PAD_CTL_PAD_GPIO_EMC_10, &nxp.IOMUXC.SW_MUX_CTL_PAD_GPIO_EMC_10 - case 11: - return &nxp.IOMUXC.SW_PAD_CTL_PAD_GPIO_EMC_11, &nxp.IOMUXC.SW_MUX_CTL_PAD_GPIO_EMC_11 - case 12: - return &nxp.IOMUXC.SW_PAD_CTL_PAD_GPIO_EMC_12, &nxp.IOMUXC.SW_MUX_CTL_PAD_GPIO_EMC_12 - case 13: - return &nxp.IOMUXC.SW_PAD_CTL_PAD_GPIO_EMC_13, &nxp.IOMUXC.SW_MUX_CTL_PAD_GPIO_EMC_13 - case 14: - return &nxp.IOMUXC.SW_PAD_CTL_PAD_GPIO_EMC_14, &nxp.IOMUXC.SW_MUX_CTL_PAD_GPIO_EMC_14 - case 15: - return &nxp.IOMUXC.SW_PAD_CTL_PAD_GPIO_EMC_15, &nxp.IOMUXC.SW_MUX_CTL_PAD_GPIO_EMC_15 - case 16: - return &nxp.IOMUXC.SW_PAD_CTL_PAD_GPIO_EMC_16, &nxp.IOMUXC.SW_MUX_CTL_PAD_GPIO_EMC_16 - case 17: - return &nxp.IOMUXC.SW_PAD_CTL_PAD_GPIO_EMC_17, &nxp.IOMUXC.SW_MUX_CTL_PAD_GPIO_EMC_17 - case 18: - return &nxp.IOMUXC.SW_PAD_CTL_PAD_GPIO_EMC_18, &nxp.IOMUXC.SW_MUX_CTL_PAD_GPIO_EMC_18 - case 19: - return &nxp.IOMUXC.SW_PAD_CTL_PAD_GPIO_EMC_19, &nxp.IOMUXC.SW_MUX_CTL_PAD_GPIO_EMC_19 - case 20: - return &nxp.IOMUXC.SW_PAD_CTL_PAD_GPIO_EMC_20, &nxp.IOMUXC.SW_MUX_CTL_PAD_GPIO_EMC_20 - case 21: - return &nxp.IOMUXC.SW_PAD_CTL_PAD_GPIO_EMC_21, &nxp.IOMUXC.SW_MUX_CTL_PAD_GPIO_EMC_21 - case 22: - return &nxp.IOMUXC.SW_PAD_CTL_PAD_GPIO_EMC_22, &nxp.IOMUXC.SW_MUX_CTL_PAD_GPIO_EMC_22 - case 23: - return &nxp.IOMUXC.SW_PAD_CTL_PAD_GPIO_EMC_23, &nxp.IOMUXC.SW_MUX_CTL_PAD_GPIO_EMC_23 - case 24: - return &nxp.IOMUXC.SW_PAD_CTL_PAD_GPIO_EMC_24, &nxp.IOMUXC.SW_MUX_CTL_PAD_GPIO_EMC_24 - case 25: - return &nxp.IOMUXC.SW_PAD_CTL_PAD_GPIO_EMC_25, &nxp.IOMUXC.SW_MUX_CTL_PAD_GPIO_EMC_25 - case 26: - return &nxp.IOMUXC.SW_PAD_CTL_PAD_GPIO_EMC_26, &nxp.IOMUXC.SW_MUX_CTL_PAD_GPIO_EMC_26 - case 27: - return &nxp.IOMUXC.SW_PAD_CTL_PAD_GPIO_EMC_27, &nxp.IOMUXC.SW_MUX_CTL_PAD_GPIO_EMC_27 - case 28: - return &nxp.IOMUXC.SW_PAD_CTL_PAD_GPIO_EMC_28, &nxp.IOMUXC.SW_MUX_CTL_PAD_GPIO_EMC_28 - case 29: - return &nxp.IOMUXC.SW_PAD_CTL_PAD_GPIO_EMC_29, &nxp.IOMUXC.SW_MUX_CTL_PAD_GPIO_EMC_29 - case 30: - return &nxp.IOMUXC.SW_PAD_CTL_PAD_GPIO_EMC_30, &nxp.IOMUXC.SW_MUX_CTL_PAD_GPIO_EMC_30 - case 31: - return &nxp.IOMUXC.SW_PAD_CTL_PAD_GPIO_EMC_31, &nxp.IOMUXC.SW_MUX_CTL_PAD_GPIO_EMC_31 - } - } - panic("machine: invalid pin") -} - -// muxSelect is yet another level of indirection required to connect pins in an -// alternate function state to a desired peripheral (since more than one pin can -// provide a given alternate function). -// -// Once a pin is configured with a given alternate function mode, the IOMUXC -// device must then be configured to select which alternate function pin to -// route to the desired peripheral. -// -// The reference manual refers to this functionality as a "Daisy Chain". The -// associated docs are found in the i.MX RT1060 Processor Reference Manual: -// "Chapter 11.3.3 Daisy chain - multi pads driving same module input pin" -type muxSelect struct { - mux uint8 // AF mux selection (NOT a Pin type) - sel *volatile.Register32 // AF selection register -} - -// connect configures the IOMUXC controller to route a given pin with alternate -// function to a desired peripheral (see godoc comments on type muxSelect). -func (s muxSelect) connect() { - s.sel.Set(uint32(s.mux)) -} - -// getMuxMode acts as a callback from the `(Pin).Configure(PinMode)` routine to -// determine the alternate function setting for a given Pin and PinConfig. -// This value is used in the IOMUXC device's SW_MUX_CTL_PAD_GPIO_* registers. -func (p Pin) getMuxMode(config PinConfig) uint32 { - const forcePath = true // TODO: should be input parameter? - switch config.Mode { - - // GPIO - case PinInput, PinInputPullup, PinInputPulldown, - PinOutput, PinOutputOpenDrain, PinDisable: - mode := uint32(0x5) // GPIO is always alternate function 5 - if forcePath { - mode |= 0x10 // SION bit - } - return mode - - // ADC - case PinInputAnalog: - mode := uint32(0x5) // use alternate function 5 (GPIO) - if forcePath { - mode |= 0x10 // SION bit - } - return mode - - // UART RX/TX - case PinModeUARTRX, PinModeUARTTX: - mode := uint32(0x2) // UART is usually alternate function 2 on Teensy 4.x - // Teensy 4.1 has a UART (LPUART5) with alternate function 1 - if p == PB28 || p == PB29 { - mode = 0x1 - } - return mode - - // SPI SDI - case PinModeSPISDI: - var mode uint32 - switch p { - case PC15: // LPSPI1 SDI on PC15 alternate function 4 - mode = uint32(0x4) - case PA2: // LPSPI3 SDI on PA2 alternate function 7 - mode = uint32(0x7) - case PB1: // LPSPI4 SDI on PB1 alternate function 3 - mode = uint32(0x3) - default: - panic("machine: invalid SPI SDI pin") - } - if forcePath { - mode |= 0x10 // SION bit - } - return mode - - // SPI SDO - case PinModeSPISDO: - var mode uint32 - switch p { - case PC14: // LPSPI1 SDO on PC14 alternate function 4 - mode = uint32(0x4) - case PA30: // LPSPI3 SDO on PA30 alternate function 2 - mode = uint32(0x2) - case PB2: // LPSPI4 SDO on PB2 alternate function 3 - mode = uint32(0x3) - default: - panic("machine: invalid SPI SDO pin") - } - if forcePath { - mode |= 0x10 // SION bit - } - return mode - - // SPI SCK - case PinModeSPICLK: - var mode uint32 - switch p { - case PC12: // LPSPI1 SCK on PC12 alternate function 4 - mode = uint32(0x4) - case PA31: // LPSPI3 SCK on PA31 alternate function 2 - mode = uint32(0x2) - case PB3: // LPSPI4 SCK on PB3 alternate function 3 - mode = uint32(0x3) - default: - panic("machine: invalid SPI CLK pin") - } - if forcePath { - mode |= 0x10 // SION bit - } - return mode - - // SPI CS - case PinModeSPICS: - var mode uint32 - switch p { - case PC13: // LPSPI1 CS on PC13 alternate function 4 - mode = uint32(0x4) - case PA3: // LPSPI3 CS on PA3 alternate function 7 - mode = uint32(0x7) - case PB0: // LPSPI4 CS on PB0 alternate function 3 - mode = uint32(0x3) - default: // use alternate function 5 (GPIO) if non-CS pin selected - mode = uint32(0x5) - } - if forcePath { - mode |= 0x10 // SION bit - } - return mode - - // I2C SDA - case PinModeI2CSDA: - var mode uint32 - switch p { - case PA13: // LPI2C4 SDA on PA13 alternate function 0 - mode = uint32(0) - case PA17: // LPI2C1 SDA on PA17 alternate function 3 - mode = uint32(3) - case PA22: // LPI2C3 SDA on PA22 alternate function 1 - mode = uint32(1) - default: - panic("machine: invalid I2C SDA pin") - } - if forcePath { - mode |= 0x10 // SION bit - } - return mode - - // I2C SCL - case PinModeI2CSCL: - var mode uint32 - switch p { - case PA12: // LPI2C4 SCL on PA12 alternate function 0 - mode = uint32(0) - case PA16: // LPI2C1 SCL on PA16 alternate function 3 - mode = uint32(3) - case PA23: // LPI2C3 SCL on PA23 alternate function 1 - mode = uint32(1) - default: - panic("machine: invalid I2C SCL pin") - } - if forcePath { - mode |= 0x10 // SION bit - } - return mode - - default: - panic("machine: invalid pin mode") - } -} - -// maximum ADC value for the currently configured resolution (used for scaling) -var adcMaximum uint32 - -// InitADC is not used by this machine. Use `(ADC).Configure()`. -func InitADC() {} - -// Configure initializes the receiver's ADC peripheral and pin for analog input. -func (a ADC) Configure(config ADCConfig) { - // if not specified, use defaults: 10-bit resolution, 4 samples/conversion - const ( - defaultResolution = uint32(10) - defaultSamples = uint32(4) - ) - - a.Pin.Configure(PinConfig{Mode: PinInputAnalog}) - - resolution, samples := config.Resolution, config.Samples - if 0 == resolution { - resolution = defaultResolution - } - if 0 == samples { - samples = defaultSamples - } - if resolution > 12 { - resolution = 12 // maximum resolution of 12 bits - } - adcMaximum = (uint32(1) << resolution) - 1 - - mode, average := a.mode(resolution, samples) - - nxp.ADC1.CFG.Set(mode | nxp.ADC_CFG_ADHSC) // configure ADC1 - nxp.ADC2.CFG.Set(mode | nxp.ADC_CFG_ADHSC) // configure ADC2 - - // begin calibration - nxp.ADC1.GC.Set(average | nxp.ADC_GC_CAL) - nxp.ADC2.GC.Set(average | nxp.ADC_GC_CAL) - - for a.isCalibrating() { - } // wait for calibration -} - -// Get performs a single ADC conversion, returning a 16-bit unsigned integer. -// The value returned will be scaled (uniformly distributed) if necessary so -// that it is always in the range [0..65535], regardless of the ADC's configured -// bit size (resolution). -func (a ADC) Get() uint16 { - if ch1, ch2, ok := a.Pin.getADCChannel(); ok { - for a.isCalibrating() { - } // wait for calibration - var val uint32 - if noADCChannel != ch1 { - nxp.ADC1.HC0.Set(uint32(ch1)) - for !nxp.ADC1.HS.HasBits(nxp.ADC_HS_COCO0) { - } - val = nxp.ADC1.R0.Get() & 0xFFFF - } else { - nxp.ADC2.HC0.Set(uint32(ch2)) - for !nxp.ADC2.HS.HasBits(nxp.ADC_HS_COCO0) { - } - val = nxp.ADC2.R0.Get() & 0xFFFF - } - // should never be zero, but just in case, use UINT16_MAX so that the scalar - // gets factored out of the conversion result, leaving the original reading - // to be returned unaltered/unscaled. - if adcMaximum == 0 { - adcMaximum = 0xFFFF - } - // scale up to a 16-bit value - return uint16((val * 0xFFFF) / adcMaximum) - } - return 0 -} - -// mode constructs bit masks for mode and average - used in ADC configuration -// registers - from a given ADC bit size (resolution) and sample count. -func (a ADC) mode(resolution, samples uint32) (mode, average uint32) { - - // use asynchronous clock (ADACK) (0 = IPG, 1 = IPG/2, or 3 = ADACK) - mode = (nxp.ADC_CFG_ADICLK_ADICLK_3 << nxp.ADC_CFG_ADICLK_Pos) & nxp.ADC_CFG_ADICLK_Msk - - // input clock DIV2 (0 = DIV1, 1 = DIV2, 2 = DIV4, or 3 = DIV8) - mode |= (nxp.ADC_CFG_ADIV_ADIV_1 << nxp.ADC_CFG_ADIV_Pos) & nxp.ADC_CFG_ADIV_Msk - - switch resolution { - case 8: // 8-bit conversion, sample period (ADC clocks) = 8 - mode |= (nxp.ADC_CFG_MODE_MODE_0 << nxp.ADC_CFG_MODE_Pos) & nxp.ADC_CFG_MODE_Msk - mode |= (nxp.ADC_CFG_ADSTS_ADSTS_3 << nxp.ADC_CFG_ADSTS_Pos) & nxp.ADC_CFG_ADSTS_Msk - - case 12: // 12-bit conversion, sample period (ADC clocks) = 24 - mode |= (nxp.ADC_CFG_MODE_MODE_2 << nxp.ADC_CFG_MODE_Pos) & nxp.ADC_CFG_MODE_Msk - mode |= (nxp.ADC_CFG_ADSTS_ADSTS_3 << nxp.ADC_CFG_ADSTS_Pos) & nxp.ADC_CFG_ADSTS_Msk - mode |= nxp.ADC_CFG_ADLSMP - - default: // 10-bit conversion, sample period (ADC clocks) = 20 - mode |= (nxp.ADC_CFG_MODE_MODE_1 << nxp.ADC_CFG_MODE_Pos) & nxp.ADC_CFG_MODE_Msk - mode |= (nxp.ADC_CFG_ADSTS_ADSTS_2 << nxp.ADC_CFG_ADSTS_Pos) & nxp.ADC_CFG_ADSTS_Msk - mode |= nxp.ADC_CFG_ADLSMP - } - - if samples >= 4 { - if samples >= 32 { - // 32 samples averaged - mode |= (nxp.ADC_CFG_AVGS_AVGS_3 << nxp.ADC_CFG_AVGS_Pos) & nxp.ADC_CFG_AVGS_Msk - } else if samples >= 16 { - // 16 samples averaged - mode |= (nxp.ADC_CFG_AVGS_AVGS_2 << nxp.ADC_CFG_AVGS_Pos) & nxp.ADC_CFG_AVGS_Msk - } else if samples >= 8 { - // 8 samples averaged - mode |= (nxp.ADC_CFG_AVGS_AVGS_1 << nxp.ADC_CFG_AVGS_Pos) & nxp.ADC_CFG_AVGS_Msk - } else { - // 4 samples averaged - mode |= (nxp.ADC_CFG_AVGS_AVGS_0 << nxp.ADC_CFG_AVGS_Pos) & nxp.ADC_CFG_AVGS_Msk - } - average = nxp.ADC_GC_AVGE - } - - return mode, average -} - -// isCalibrating returns true if and only if either one (or both) of ADC1 and -// ADC2 have their calibrating flags set. ADC reads must wait until these flags -// are clear before attempting a conversion. -func (a ADC) isCalibrating() bool { - return nxp.ADC1.GC.HasBits(nxp.ADC_GC_CAL) || nxp.ADC2.GC.HasBits(nxp.ADC_GC_CAL) -} - -const noADCChannel = uint8(0xFF) - -// getADCChannel returns the input channel for ADC1/ADC2 of the receiver Pin p. -func (p Pin) getADCChannel() (adc1, adc2 uint8, ok bool) { - switch p { - case PA12: // [AD_B0_12]: ADC1_IN1 ~ - return 1, noADCChannel, true - case PA13: // [AD_B0_13]: ADC1_IN2 ~ - return 2, noADCChannel, true - case PA14: // [AD_B0_14]: ADC1_IN3 ~ - return 3, noADCChannel, true - case PA15: // [AD_B0_15]: ADC1_IN4 ~ - return 4, noADCChannel, true - case PA16: // [AD_B1_00]: ADC1_IN5 ADC2_IN5 - return 5, 5, true - case PA17: // [AD_B1_01]: ADC1_IN6 ADC2_IN6 - return 6, 6, true - case PA18: // [AD_B1_02]: ADC1_IN7 ADC2_IN7 - return 7, 7, true - case PA19: // [AD_B1_03]: ADC1_IN8 ADC2_IN8 - return 8, 8, true - case PA20: // [AD_B1_04]: ADC1_IN9 ADC2_IN9 - return 9, 9, true - case PA21: // [AD_B1_05]: ADC1_IN10 ADC2_IN10 - return 10, 10, true - case PA22: // [AD_B1_06]: ADC1_IN11 ADC2_IN11 - return 11, 11, true - case PA23: // [AD_B1_07]: ADC1_IN12 ADC2_IN12 - return 12, 12, true - case PA24: // [AD_B1_08]: ADC1_IN13 ADC2_IN13 - return 13, 13, true - case PA25: // [AD_B1_09]: ADC1_IN14 ADC2_IN14 - return 14, 14, true - case PA26: // [AD_B1_10]: ADC1_IN15 ADC2_IN15 - return 15, 15, true - case PA27: // [AD_B1_11]: ADC1_IN0 ADC2_IN0 - return 16, 16, true - case PA28: // [AD_B1_12]: ~ ADC2_IN1 - return noADCChannel, 1, true - case PA29: // [AD_B1_13]: ~ ADC2_IN2 - return noADCChannel, 2, true - case PA30: // [AD_B1_14]: ~ ADC2_IN3 - return noADCChannel, 3, true - case PA31: // [AD_B1_15]: ~ ADC2_IN4 - return noADCChannel, 4, true - default: - return noADCChannel, noADCChannel, false - } -} diff --git a/emb/machine/machine_mimxrt1062_i2c.go b/emb/machine/machine_mimxrt1062_i2c.go deleted file mode 100644 index f3c4636..0000000 --- a/emb/machine/machine_mimxrt1062_i2c.go +++ /dev/null @@ -1,642 +0,0 @@ -//go:build mimxrt1062 - -package machine - -// I2C peripheral abstraction layer for the MIMXRT1062 - -import ( - "device/nxp" -) - -// I2CConfig is used to store config info for I2C. -type I2CConfig struct { - Frequency uint32 - SDA Pin - SCL Pin -} - -type I2C struct { - Bus *nxp.LPI2C_Type - - // these pins are initialized by each global I2C variable declared in the - // board_teensy4x.go file according to the board manufacturer's default pin - // mapping. they can be overridden with the I2CConfig argument given to - // (*I2C) Configure(I2CConfig). - sda, scl Pin - - // these hold the input selector ("daisy chain") values that select which pins - // are connected to the LPI2C device, and should be defined where the I2C - // instance is declared (e.g., in the board definition). see the godoc - // comments on type muxSelect for more details. - muxSDA, muxSCL muxSelect -} - -type i2cDirection bool - -const ( - directionWrite i2cDirection = false - directionRead i2cDirection = true -) - -func (dir i2cDirection) shift(addr uint16) uint32 { - if addr <<= 1; dir == directionRead { - addr |= 1 - } - return uint32(addr) & 0xFF -} - -// I2C enumerated types -type ( - resultFlag uint32 - statusFlag uint32 - transferFlag uint32 - commandFlag uint32 - stateFlag uint32 -) - -const ( - // general purpose results - resultSuccess resultFlag = 0x0 // success - resultFail resultFlag = 0x1 // fail - resultReadOnly resultFlag = 0x2 // read only failure - resultOutOfRange resultFlag = 0x3 // out of range access - resultInvalidArgument resultFlag = 0x4 // invalid argument check - // I2C-specific results - resultBusy resultFlag = 0x0384 + 0x0 // the controller is already performing a transfer - resultIdle resultFlag = 0x0384 + 0x1 // the peripheral driver is idle - resultNak resultFlag = 0x0384 + 0x2 // the peripheral device sent a NAK in response to a byte - resultFifoError resultFlag = 0x0384 + 0x3 // FIFO under run or overrun - resultBitError resultFlag = 0x0384 + 0x4 // transferred bit was not seen on the bus - resultArbitrationLost resultFlag = 0x0384 + 0x5 // arbitration lost error - resultPinLowTimeout resultFlag = 0x0384 + 0x6 // SCL or SDA were held low longer than the timeout - resultNoTransferInProgress resultFlag = 0x0384 + 0x7 // attempt to abort a transfer when one is not in progress - resultDmaRequestFail resultFlag = 0x0384 + 0x8 // DMA request failed - resultTimeout resultFlag = 0x0384 + 0x9 // timeout polling status flags -) - -const ( - statusTxReady statusFlag = nxp.LPI2C_MSR_TDF // transmit data flag - statusRxReady statusFlag = nxp.LPI2C_MSR_RDF // receive data flag - statusEndOfPacket statusFlag = nxp.LPI2C_MSR_EPF // end Packet flag - statusStopDetect statusFlag = nxp.LPI2C_MSR_SDF // stop detect flag - statusNackDetect statusFlag = nxp.LPI2C_MSR_NDF // NACK detect flag - statusArbitrationLost statusFlag = nxp.LPI2C_MSR_ALF // arbitration lost flag - statusFifoErr statusFlag = nxp.LPI2C_MSR_FEF // FIFO error flag - statusPinLowTimeout statusFlag = nxp.LPI2C_MSR_PLTF // pin low timeout flag - statusI2CDataMatch statusFlag = nxp.LPI2C_MSR_DMF // data match flag - statusBusy statusFlag = nxp.LPI2C_MSR_MBF // busy flag - statusBusBusy statusFlag = nxp.LPI2C_MSR_BBF // bus busy flag - - // all flags which are cleared by the driver upon starting a transfer - statusClear statusFlag = statusEndOfPacket | statusStopDetect | statusNackDetect | - statusArbitrationLost | statusFifoErr | statusPinLowTimeout | statusI2CDataMatch - - // IRQ sources enabled by the non-blocking transactional API - statusIrq statusFlag = statusArbitrationLost | statusTxReady | statusRxReady | - statusStopDetect | statusNackDetect | statusPinLowTimeout | statusFifoErr - - // errors to check for - statusError statusFlag = statusNackDetect | statusArbitrationLost | statusFifoErr | - statusPinLowTimeout -) - -// LPI2C transfer modes -const ( - transferDefault transferFlag = 0x0 // transfer starts with a start signal, stops with a stop signal - transferNoStart transferFlag = 0x1 // don't send a start condition, address, and sub address - transferRepeatedStart transferFlag = 0x2 // send a repeated start condition - transferNoStop transferFlag = 0x4 // don't send a stop condition -) - -// LPI2C FIFO commands -const ( - commandTxData commandFlag = (0x0 << nxp.LPI2C_MTDR_CMD_Pos) & nxp.LPI2C_MTDR_CMD_Msk // transmit - commandRxData commandFlag = (0x1 << nxp.LPI2C_MTDR_CMD_Pos) & nxp.LPI2C_MTDR_CMD_Msk // receive - commandStop commandFlag = (0x2 << nxp.LPI2C_MTDR_CMD_Pos) & nxp.LPI2C_MTDR_CMD_Msk // generate STOP condition - commandStart commandFlag = (0x4 << nxp.LPI2C_MTDR_CMD_Pos) & nxp.LPI2C_MTDR_CMD_Msk // generate (REPEATED)START and transmit -) - -// LPI2C transactional states -const ( - stateIdle stateFlag = 0x0 - stateSendCommand stateFlag = 0x1 - stateIssueReadCommand stateFlag = 0x2 - stateTransferData stateFlag = 0x3 - stateStop stateFlag = 0x4 - stateWaitForCompletion stateFlag = 0x5 -) - -func (i2c *I2C) setPins(c I2CConfig) (sda, scl Pin) { - // if both given pins are defined, or either receiver pin is undefined. - if 0 != c.SDA && 0 != c.SCL || 0 == i2c.sda || 0 == i2c.scl { - // override the receiver's pins. - i2c.sda, i2c.scl = c.SDA, c.SCL - } - // return the selected pins. - return i2c.sda, i2c.scl -} - -// Configure is intended to setup an I2C interface for transmit/receive. -func (i2c *I2C) Configure(config I2CConfig) error { - // init pins - sda, scl := i2c.setPins(config) - - // configure the mux and pad control registers - sda.Configure(PinConfig{Mode: PinModeI2CSDA}) - scl.Configure(PinConfig{Mode: PinModeI2CSCL}) - - // configure the mux input selector - i2c.muxSDA.connect() - i2c.muxSCL.connect() - - freq := config.Frequency - if 0 == freq { - freq = 100 * KHz - } - - // reset clock and registers, and enable LPI2C module interface - i2c.reset(freq) - - return nil -} - -// SetBaudRate sets the communication speed for I2C. -func (i2c I2C) SetBaudRate(br uint32) error { - // TODO: implement - return errI2CNotImplemented -} - -func (i2c I2C) Tx(addr uint16, w, r []byte) error { - // perform transmit transfer - if nil != w { - // generate start condition on bus - if result := i2c.start(addr, directionWrite); resultSuccess != result { - return errI2CSignalStartTimeout - } - // ensure TX FIFO is empty - if result := i2c.waitForTxEmpty(); resultSuccess != result { - return errI2CBusReadyTimeout - } - // check if communication was successful - if status := statusFlag(i2c.Bus.MSR.Get()); 0 != (status & statusNackDetect) { - return errI2CAckExpected - } - // send transmit data - if result := i2c.controllerTransmit(w); resultSuccess != result { - return errI2CWriteTimeout - } - } - - // perform receive transfer - if nil != r { - // generate (repeated-)start condition on bus - if result := i2c.start(addr, directionRead); resultSuccess != result { - return errI2CSignalStartTimeout - } - // read received data - if result := i2c.controllerReceive(r); resultSuccess != result { - return errI2CReadTimeout - } - } - - // generate stop condition on bus - if result := i2c.stop(); resultSuccess != result { - return errI2CSignalStopTimeout - } - - return nil -} - -// WriteRegisterEx transmits first the register and then the data to the -// peripheral device. -// -// Many I2C-compatible devices are organized in terms of registers. This method -// is a shortcut to easily write to such registers. Also, it only works for -// devices with 7-bit addresses, which is the vast majority. -func (i2c I2C) WriteRegisterEx(address uint8, register uint8, data []byte) error { - option := transferOption{ - flags: transferDefault, // transfer options bit mask (0 = normal transfer) - peripheral: uint16(address), // 7-bit peripheral address - direction: directionWrite, // directionRead or directionWrite - subaddress: uint16(register), // peripheral sub-address (transferred MSB first) - subaddressSize: 1, // byte length of sub-address (maximum = 4 bytes) - } - if result := i2c.controllerTransferPoll(option, data); resultSuccess != result { - return errI2CWriteTimeout - } - return nil -} - -// ReadRegisterEx transmits the register, restarts the connection as a read -// operation, and reads the response. -// -// Many I2C-compatible devices are organized in terms of registers. This method -// is a shortcut to easily read such registers. Also, it only works for devices -// with 7-bit addresses, which is the vast majority. -func (i2c I2C) ReadRegisterEx(address uint8, register uint8, data []byte) error { - option := transferOption{ - flags: transferDefault, // transfer options bit mask (0 = normal transfer) - peripheral: uint16(address), // 7-bit peripheral address - direction: directionRead, // directionRead or directionWrite - subaddress: uint16(register), // peripheral sub-address (transferred MSB first) - subaddressSize: 1, // byte length of sub-address (maximum = 4 bytes) - } - if result := i2c.controllerTransferPoll(option, data); resultSuccess != result { - return errI2CWriteTimeout - } - return nil -} - -func (i2c *I2C) reset(freq uint32) { - // disable interface - i2c.Bus.MCR.ClearBits(nxp.LPI2C_MCR_MEN) - - // software reset all interface registers - i2c.Bus.MCR.Set(nxp.LPI2C_MCR_RST) - - // RST remains set until manually cleared! - i2c.Bus.MCR.ClearBits(nxp.LPI2C_MCR_RST) - - // disable host request - i2c.Bus.MCFGR0.Set(0) - - // enable ACK, use I2C 2-pin open drain mode - i2c.Bus.MCFGR1.Set(0) - - // set FIFO watermarks (RX=1, TX=1) - mfcr := (uint32(0x1) << nxp.LPI2C_MFCR_RXWATER_Pos) & nxp.LPI2C_MFCR_RXWATER_Msk - mfcr |= (uint32(0x1) << nxp.LPI2C_MFCR_TXWATER_Pos) & nxp.LPI2C_MFCR_TXWATER_Msk - i2c.Bus.MFCR.Set(mfcr) - - // configure clock using receiver frequency - i2c.setFrequency(freq) - - // clear reset, and enable the interface - i2c.Bus.MCR.Set(nxp.LPI2C_MCR_MEN) - - // wait for the I2C bus to idle - for i2c.Bus.MSR.Get()&nxp.LPI2C_MSR_BBF != 0 { - } -} - -func (i2c *I2C) setFrequency(freq uint32) { - var ( - bestPre uint32 = 0 - bestClkHi uint32 = 0 - bestError uint32 = 0xFFFFFFFF - ) - - // disable interface - wasEnabled := i2c.Bus.MCR.HasBits(nxp.LPI2C_MCR_MEN) - i2c.Bus.MCR.ClearBits(nxp.LPI2C_MCR_MEN) - - // baud rate = (24MHz/(2^pre))/(CLKLO+1 + CLKHI+1 + FLOOR((2+FILTSCL)/(2^pre))) - // assume: CLKLO=2*CLKHI, SETHOLD=CLKHI, DATAVD=CLKHI/2 - for pre := uint32(1); pre <= 128; pre *= 2 { - if bestError == 0 { - break - } - for clkHi := uint32(1); clkHi < 32; clkHi++ { - var absError, rate uint32 - if clkHi == 1 { - rate = (24 * MHz / pre) / (1 + 3 + 2 + 2/pre) - } else { - rate = (24 * MHz / pre) / (3*clkHi + 2 + 2/pre) - } - if freq > rate { - absError = freq - rate - } else { - absError = rate - freq - } - if absError < bestError { - bestPre = pre - bestClkHi = clkHi - bestError = absError - // if the error is 0, then we can stop searching because we won't find a - // better match - if absError == 0 { - break - } - } - } - } - - var ( - clklo = func(n uint32) uint32 { return (n << nxp.LPI2C_MCCR0_CLKLO_Pos) & nxp.LPI2C_MCCR0_CLKLO_Msk } - clkhi = func(n uint32) uint32 { return (n << nxp.LPI2C_MCCR0_CLKHI_Pos) & nxp.LPI2C_MCCR0_CLKHI_Msk } - datavd = func(n uint32) uint32 { return (n << nxp.LPI2C_MCCR0_DATAVD_Pos) & nxp.LPI2C_MCCR0_DATAVD_Msk } - sethold = func(n uint32) uint32 { return (n << nxp.LPI2C_MCCR0_SETHOLD_Pos) & nxp.LPI2C_MCCR0_SETHOLD_Msk } - ) - // StandardMode, FastMode, FastModePlus, and UltraFastMode - mccr0 := clkhi(bestClkHi) - if bestClkHi < 2 { - mccr0 |= (clklo(3) | sethold(2) | datavd(1)) - } else { - mccr0 |= clklo(2*bestClkHi) | sethold(bestClkHi) | datavd(bestClkHi/2) - } - i2c.Bus.MCCR0.Set(mccr0) - i2c.Bus.MCCR1.Set(i2c.Bus.MCCR0.Get()) - - for i := uint32(0); i < 8; i++ { - if bestPre == (1 << i) { - bestPre = i - break - } - } - preMask := (bestPre << nxp.LPI2C_MCFGR1_PRESCALE_Pos) & nxp.LPI2C_MCFGR1_PRESCALE_Msk - i2c.Bus.MCFGR1.Set((i2c.Bus.MCFGR1.Get() & ^uint32(nxp.LPI2C_MCFGR1_PRESCALE_Msk)) | preMask) - - var ( - filtsda = func(n uint32) uint32 { return (n << nxp.LPI2C_MCFGR2_FILTSDA_Pos) & nxp.LPI2C_MCFGR2_FILTSDA_Msk } - filtscl = func(n uint32) uint32 { return (n << nxp.LPI2C_MCFGR2_FILTSCL_Pos) & nxp.LPI2C_MCFGR2_FILTSCL_Msk } - busidle = func(n uint32) uint32 { return (n << nxp.LPI2C_MCFGR2_BUSIDLE_Pos) & nxp.LPI2C_MCFGR2_BUSIDLE_Msk } - pinlow = func(n uint32) uint32 { return (n << nxp.LPI2C_MCFGR3_PINLOW_Pos) & nxp.LPI2C_MCFGR3_PINLOW_Msk } - - mcfgr2, mcfgr3 uint32 - ) - const i2cClockStretchTimeout = 15000 // microseconds - if freq >= 5*MHz { - // I2C UltraFastMode 5 MHz - mcfgr2 = 0 // disable glitch filters and timeout for UltraFastMode - mcfgr3 = 0 // - } else if freq >= 1*MHz { - // I2C FastModePlus 1 MHz - mcfgr2 = filtsda(1) | filtscl(1) | busidle(2400) // 100us timeout - mcfgr3 = pinlow(i2cClockStretchTimeout*24/256 + 1) - } else if freq >= 400*KHz { - // I2C FastMode 400 kHz - mcfgr2 = filtsda(2) | filtscl(2) | busidle(3600) // 150us timeout - mcfgr3 = pinlow(i2cClockStretchTimeout*24/256 + 1) - } else { - // I2C StandardMode 100 kHz - mcfgr2 = filtsda(5) | filtscl(5) | busidle(3000) // 250us timeout - mcfgr3 = pinlow(i2cClockStretchTimeout*12/256 + 1) - } - i2c.Bus.MCFGR2.Set(mcfgr2) - i2c.Bus.MCFGR3.Set(mcfgr3) - - // restore controller mode if it was enabled when called - if wasEnabled { - i2c.Bus.MCR.SetBits(nxp.LPI2C_MCR_MEN) - } -} - -// checkStatus converts the status register to a resultFlag for return, and -// clears any errors if present. -func (i2c *I2C) checkStatus(status statusFlag) resultFlag { - result := resultSuccess - // check for error. these errors cause a stop to be sent automatically. - // we must clear the errors before a new transfer can start. - if status &= statusError; 0 != status { - // select the correct error code ordered by severity, bus issues first. - if 0 != (status & statusPinLowTimeout) { - result = resultPinLowTimeout - } else if 0 != (status & statusArbitrationLost) { - result = resultArbitrationLost - } else if 0 != (status & statusNackDetect) { - result = resultNak - } else if 0 != (status & statusFifoErr) { - result = resultFifoError - } - // clear the flags - i2c.Bus.MSR.Set(uint32(status)) - // reset fifos. these flags clear automatically. - i2c.Bus.MCR.SetBits(nxp.LPI2C_MCR_RRF | nxp.LPI2C_MCR_RTF) - } - return result -} - -func (i2c *I2C) getFIFOSize() (rx, tx uint32) { return 4, 4 } -func (i2c *I2C) getFIFOCount() (rx, tx uint32) { - mfsr := i2c.Bus.MFSR.Get() - return (mfsr & nxp.LPI2C_MFSR_RXCOUNT_Msk) >> nxp.LPI2C_MFSR_RXCOUNT_Pos, - (mfsr & nxp.LPI2C_MFSR_TXCOUNT_Msk) >> nxp.LPI2C_MFSR_TXCOUNT_Pos -} - -func (i2c *I2C) waitForTxReady() resultFlag { - result := resultSuccess - _, txSize := i2c.getFIFOSize() - for { - _, txCount := i2c.getFIFOCount() - status := statusFlag(i2c.Bus.MSR.Get()) - if result = i2c.checkStatus(status); resultSuccess != result { - break - } - if txSize-txCount > 0 { - break - } - } - return result -} - -func (i2c *I2C) waitForTxEmpty() resultFlag { - result := resultSuccess - for { - _, txCount := i2c.getFIFOCount() - status := statusFlag(i2c.Bus.MSR.Get()) - if result = i2c.checkStatus(status); resultSuccess != result { - break - } - if 0 == txCount { - break - } - } - return result -} - -// isBusBusy checks if the I2C bus is busy, returning true if it is busy and we -// are not the ones driving it, otherwise false. -func (i2c *I2C) isBusBusy() bool { - status := statusFlag(i2c.Bus.MSR.Get()) - return (0 != (status & statusBusBusy)) && (0 == (status & statusBusy)) -} - -// start sends a START signal and peripheral address on the I2C bus. -// -// This function is used to initiate a new controller mode transfer. First, the -// bus state is checked to ensure that another controller is not occupying the -// bus. Then a START signal is transmitted, followed by the 7-bit peripheral -// address. Note that this function does not actually wait until the START and -// address are successfully sent on the bus before returning. -func (i2c *I2C) start(address uint16, dir i2cDirection) resultFlag { - // return an error if the bus is already in use by another controller - if i2c.isBusBusy() { - return resultBusy - } - // clear all flags - i2c.Bus.MSR.Set(uint32(statusClear)) - // turn off auto-stop - i2c.Bus.MCFGR1.ClearBits(nxp.LPI2C_MCFGR1_AUTOSTOP) - // wait until there is room in the FIFO - if result := i2c.waitForTxReady(); resultSuccess != result { - return result - } - - // issue start command - i2c.Bus.MTDR.Set(uint32(commandStart) | dir.shift(address)) - return resultSuccess -} - -// stop sends a STOP signal on the I2C bus. -// -// This function does not return until the STOP signal is seen on the bus, or -// an error occurs. -func (i2c *I2C) stop() resultFlag { - const tryMax = 0 // keep waiting forever - // wait until there is room in the FIFO - result := i2c.waitForTxReady() - if resultSuccess != result { - return result - } - // send the STOP signal - i2c.Bus.MTDR.Set(uint32(commandStop)) - // wait for the stop detected flag to set, indicating the transfer has - // completed on the bus. also check for errors while waiting. - try := 0 - for resultSuccess == result && (0 == tryMax || try < tryMax) { - status := statusFlag(i2c.Bus.MSR.Get()) - result = i2c.checkStatus(status) - if (0 != (status & statusStopDetect)) && (0 != (status & statusTxReady)) { - i2c.Bus.MSR.Set(uint32(statusStopDetect)) - break - } - try++ - } - if 0 != tryMax && try >= tryMax { - return resultTimeout - } - return result -} - -// controllerReceive performs a polling receive transfer on the I2C bus. -func (i2c *I2C) controllerReceive(rxBuffer []byte) resultFlag { - const tryMax = 0 // keep trying forever - rxSize := len(rxBuffer) - if rxSize == 0 { - return resultSuccess - } - // wait until there is room in the FIFO - result := i2c.waitForTxReady() - if resultSuccess != result { - return result - } - sizeMask := (uint32(rxSize-1) << nxp.LPI2C_MTDR_DATA_Pos) & nxp.LPI2C_MTDR_DATA_Msk - i2c.Bus.MTDR.Set(uint32(commandRxData) | sizeMask) - - // receive data - for rxSize > 0 { - // read LPI2C receive FIFO register. the register includes a flag to - // indicate whether the FIFO is empty, so we can both get the data and check - // if we need to keep reading using a single register read. - var data uint32 - try := 0 - for 0 == tryMax || try < tryMax { - // check for errors on the bus - status := statusFlag(i2c.Bus.MSR.Get()) - result = i2c.checkStatus(status) - if resultSuccess != result { - return result - } - // read received data, break if FIFO was non-empty - data = i2c.Bus.MRDR.Get() - if 0 == (data & nxp.LPI2C_MRDR_RXEMPTY_Msk) { - break - } - try++ - } - // ensure we didn't timeout waiting for data - if 0 != tryMax && try >= tryMax { - return resultTimeout - } - // copy data to RX buffer - rxBuffer[len(rxBuffer)-rxSize] = byte(data & nxp.LPI2C_MRDR_DATA_Msk) - rxSize-- - } - return result -} - -// controllerTransmit performs a polling transmit transfer on the I2C bus. -func (i2c *I2C) controllerTransmit(txBuffer []byte) resultFlag { - txSize := len(txBuffer) - for txSize > 0 { - // wait until there is room in the FIFO - result := i2c.waitForTxReady() - if resultSuccess != result { - return result - } - // write byte into LPI2C data register - i2c.Bus.MTDR.Set(uint32(txBuffer[len(txBuffer)-txSize] & nxp.LPI2C_MTDR_DATA_Msk)) - txSize-- - } - return resultSuccess -} - -type transferOption struct { - flags transferFlag // transfer options bit mask (0 = normal transfer) - peripheral uint16 // 7-bit peripheral address - direction i2cDirection // directionRead or directionWrite - subaddress uint16 // peripheral sub-address (transferred MSB first) - subaddressSize uint16 // byte length of sub-address (maximum = 4 bytes) -} - -func (i2c *I2C) controllerTransferPoll(option transferOption, data []byte) resultFlag { - // return an error if the bus is already in use by another controller - if i2c.isBusBusy() { - return resultBusy - } - // clear all flags - i2c.Bus.MSR.Set(uint32(statusClear)) - // turn off auto-stop - i2c.Bus.MCFGR1.ClearBits(nxp.LPI2C_MCFGR1_AUTOSTOP) - - cmd := make([]uint16, 0, 7) - size := len(data) - - direction := option.direction - if option.subaddressSize > 0 { - direction = directionWrite - } - // peripheral address - if 0 == (option.flags & transferNoStart) { - addr := direction.shift(option.peripheral) - cmd = append(cmd, uint16(uint32(commandStart)|addr)) - } - // sub-address (MSB-first) - rem := option.subaddressSize - for rem > 0 { - rem-- - cmd = append(cmd, (option.subaddress>>(8*rem))&0xFF) - } - // need to send repeated start if switching directions to read - if (0 != size) && (directionRead == option.direction) { - if directionWrite == direction { - addr := directionRead.shift(option.peripheral) - cmd = append(cmd, uint16(uint32(commandStart)|addr)) - } - } - // send command buffer - result := resultSuccess - for _, c := range cmd { - // wait until there is room in the FIFO - if result = i2c.waitForTxReady(); resultSuccess != result { - return result - } - // write byte into LPI2C controller data register - i2c.Bus.MTDR.Set(uint32(c)) - } - // send data - if option.direction == directionWrite && size > 0 { - result = i2c.controllerTransmit(data) - } - // receive data - if option.direction == directionRead && size > 0 { - result = i2c.controllerReceive(data) - } - if resultSuccess != result { - return result - } - if 0 == (option.flags & transferNoStop) { - result = i2c.stop() - } - return result -} diff --git a/emb/machine/machine_mimxrt1062_spi.go b/emb/machine/machine_mimxrt1062_spi.go deleted file mode 100644 index d982eea..0000000 --- a/emb/machine/machine_mimxrt1062_spi.go +++ /dev/null @@ -1,254 +0,0 @@ -//go:build mimxrt1062 - -package machine - -// SPI peripheral abstraction layer for the MIMXRT1062 - -import ( - "device/nxp" - "errors" - "unsafe" -) - -// SPIConfig is used to store config info for SPI. -type SPIConfig struct { - Frequency uint32 - SDI Pin - SDO Pin - SCK Pin - CS Pin - LSBFirst bool - Mode uint8 -} - -func (c SPIConfig) getPins() (di, do, ck, cs Pin) { - if 0 == c.SDI && 0 == c.SDO && 0 == c.SCK && 0 == c.CS { - // default pins if none specified - return SPI_SDI_PIN, SPI_SDO_PIN, SPI_SCK_PIN, SPI_CS_PIN - } - return c.SDI, c.SDO, c.SCK, c.CS -} - -type SPI struct { - Bus *nxp.LPSPI_Type - - // these hold the input selector ("daisy chain") values that select which pins - // are connected to the LPSPI device, and should be defined where the SPI - // instance is declared (e.g., in the board definition). see the godoc - // comments on type muxSelect for more details. - muxSDI, muxSDO, muxSCK, muxCS muxSelect - - // these are copied from SPIConfig, during (*SPI).Configure(SPIConfig), and - // should be considered read-only for internal reference (i.e., modifying them - // will have no desirable effect). - sdi, sdo, sck, cs Pin - frequency uint32 - - // auxiliary state data used internally - configured bool -} - -const ( - statusTxDataRequest = nxp.LPSPI_SR_TDF // Transmit data flag - statusRxDataReady = nxp.LPSPI_SR_RDF // Receive data flag - statusWordComplete = nxp.LPSPI_SR_WCF // Word Complete flag - statusFrameComplete = nxp.LPSPI_SR_FCF // Frame Complete flag - statusTransferComplete = nxp.LPSPI_SR_TCF // Transfer Complete flag - statusTransmitError = nxp.LPSPI_SR_TEF // Transmit Error flag (FIFO underrun) - statusReceiveError = nxp.LPSPI_SR_REF // Receive Error flag (FIFO overrun) - statusDataMatch = nxp.LPSPI_SR_DMF // Data Match flag - statusModuleBusy = nxp.LPSPI_SR_MBF // Module Busy flag - statusAll = nxp.LPSPI_SR_TDF | nxp.LPSPI_SR_RDF | - nxp.LPSPI_SR_WCF | nxp.LPSPI_SR_FCF | nxp.LPSPI_SR_TCF | nxp.LPSPI_SR_TEF | - nxp.LPSPI_SR_REF | nxp.LPSPI_SR_DMF | nxp.LPSPI_SR_MBF -) - -var ( - errSPINotConfigured = errors.New("SPI interface is not yet configured") -) - -// Configure is intended to setup an SPI interface for transmit/receive. -func (spi *SPI) Configure(config SPIConfig) error { - - const defaultSpiFreq = 4000000 // 4 MHz - - // init pins - spi.sdi, spi.sdo, spi.sck, spi.cs = config.getPins() - - // configure the mux and pad control registers - spi.sdi.Configure(PinConfig{Mode: PinModeSPISDI}) - spi.sdo.Configure(PinConfig{Mode: PinModeSPISDO}) - spi.sck.Configure(PinConfig{Mode: PinModeSPICLK}) - spi.cs.Configure(PinConfig{Mode: PinModeSPICS}) - - // configure the mux input selector - spi.muxSDI.connect() - spi.muxSDO.connect() - spi.muxSCK.connect() - spi.muxCS.connect() - - // software reset of LPSPI state registers - spi.Bus.CR.SetBits(nxp.LPSPI_CR_RST) - // also reset FIFOs (not performed by software reset above) - spi.Bus.CR.SetBits(nxp.LPSPI_CR_RRF | nxp.LPSPI_CR_RTF) - spi.Bus.CR.Set(0) - - // set controller mode, and input data is sampled on delayed SCK edge - spi.Bus.CFGR1.Set(nxp.LPSPI_CFGR1_MASTER | nxp.LPSPI_CFGR1_SAMPLE) - - spi.frequency = config.Frequency - if 0 == spi.frequency { - spi.frequency = defaultSpiFreq - } - - // configure LPSPI clock divisor and CS assertion delays - div := spi.getClockDivisor(config.Frequency) - ccr := (div << nxp.LPSPI_CCR_SCKDIV_Pos) & nxp.LPSPI_CCR_SCKDIV_Msk - ccr |= ((div / 2) << nxp.LPSPI_CCR_DBT_Pos) & nxp.LPSPI_CCR_DBT_Msk - ccr |= ((div / 2) << nxp.LPSPI_CCR_PCSSCK_Pos) & nxp.LPSPI_CCR_PCSSCK_Msk - spi.Bus.CCR.Set(ccr) - - // 8-bit frame size (words) - tcr := uint32(7) - if config.LSBFirst { - tcr |= nxp.LPSPI_TCR_LSBF - } - // set polarity and phase - switch config.Mode { - case Mode1: - tcr |= nxp.LPSPI_TCR_CPHA - case Mode2: - tcr |= nxp.LPSPI_TCR_CPOL - case Mode3: - tcr |= nxp.LPSPI_TCR_CPOL - tcr |= nxp.LPSPI_TCR_CPHA - } - spi.Bus.TCR.Set(tcr) - - // clear FIFO water marks - spi.setWatermark(0, 0) - - // enable LPSPI module - spi.Bus.CR.Set(nxp.LPSPI_CR_MEN) - - spi.configured = true - - return nil -} - -// Transfer writes/reads a single byte using the SPI interface. -func (spi *SPI) Transfer(w byte) (byte, error) { - if !spi.configured { - return 0, errSPINotConfigured - } - - const readTryMax = 10000 - - for spi.Bus.SR.HasBits(statusModuleBusy) { - } // wait for SPI busy bit to clear - - _, txFIFOSize := spi.getFIFOSize() - - spi.flushFIFO(true, true) - spi.Bus.SR.Set(statusAll) // clear all status flags (W1C) - - // enable LPSPI module - spi.Bus.CR.Set(nxp.LPSPI_CR_MEN) - - // TODO: unnecessary since we just flushed the FIFO? - for { // wait for TX FIFO to not be full - if _, txFIFO := spi.getFIFOCount(); txFIFO < txFIFOSize { - break - } - } - - // write out byte to TX FIFO - spi.Bus.TDR.Set(uint32(w)) - - // try to read from RX FIFO if anything exists - didRead := false - data := byte(0) - for i := 0; !didRead && (i < readTryMax); i++ { - rxFIFO, _ := spi.getFIFOCount() - didRead = rxFIFO > 0 - if didRead { - data = byte(spi.Bus.RDR.Get()) - } - } - - // if nothing was read, then wait for transfer complete flag to decide when - // we are finished - if !didRead { - for !spi.Bus.SR.HasBits(nxp.LPSPI_SR_TCF) { - } // wait for all transfers complete flag to set - } - - return data, nil -} - -func (spi *SPI) isHardwareCSPin(pin Pin) bool { - switch unsafe.Pointer(spi.Bus) { - case unsafe.Pointer(nxp.LPSPI1): - return SPI1_CS_PIN == pin - case unsafe.Pointer(nxp.LPSPI2): - return SPI2_CS_PIN == pin - case unsafe.Pointer(nxp.LPSPI3): - return SPI3_CS_PIN == pin - } - return false -} - -func (spi *SPI) hasHardwareCSPin() bool { - return spi.isHardwareCSPin(spi.cs) -} - -// getClockDivisor finds the SPI prescalar that minimizes the error between -// requested frequency and possible frequencies available with the LPSPI clock. -// this routine is based on Teensyduino (libraries/SPI/SPI.cpp): -// -// void SPIClass::setClockDivider_noInline(uint32_t clk) -func (spi *SPI) getClockDivisor(freq uint32) uint32 { - const clock = 132000000 // LPSPI root clock frequency (PLL2) - d := uint32(clock) - if freq > 0 { - d /= freq - } - if d > 0 && clock/d > freq { - d++ - } - if d > 257 { - return 255 - } - if d > 2 { - return d - 2 - } - return 0 -} - -func (spi *SPI) getFIFOSize() (rx, tx uint32) { - param := spi.Bus.PARAM.Get() - return uint32(1) << ((param & nxp.LPSPI_PARAM_RXFIFO_Msk) >> nxp.LPSPI_PARAM_RXFIFO_Pos), - uint32(1) << ((param & nxp.LPSPI_PARAM_TXFIFO_Msk) >> nxp.LPSPI_PARAM_TXFIFO_Pos) -} - -func (spi *SPI) getFIFOCount() (rx, tx uint32) { - fsr := spi.Bus.FSR.Get() - return (fsr & nxp.LPSPI_FSR_RXCOUNT_Msk) >> nxp.LPSPI_FSR_RXCOUNT_Pos, - (fsr & nxp.LPSPI_FSR_TXCOUNT_Msk) >> nxp.LPSPI_FSR_TXCOUNT_Pos -} - -func (spi *SPI) flushFIFO(rx, tx bool) { - var flush uint32 - if rx { - flush |= nxp.LPSPI_CR_RRF - } - if tx { - flush |= nxp.LPSPI_CR_RTF - } - spi.Bus.CR.SetBits(flush) -} - -func (spi *SPI) setWatermark(rx, tx uint32) { - spi.Bus.FCR.Set(((rx << nxp.LPSPI_FCR_RXWATER_Pos) & nxp.LPSPI_FCR_RXWATER_Msk) | - ((tx << nxp.LPSPI_FCR_TXWATER_Pos) & nxp.LPSPI_FCR_TXWATER_Msk)) -} diff --git a/emb/machine/machine_mimxrt1062_uart.go b/emb/machine/machine_mimxrt1062_uart.go deleted file mode 100644 index 6265b85..0000000 --- a/emb/machine/machine_mimxrt1062_uart.go +++ /dev/null @@ -1,303 +0,0 @@ -//go:build mimxrt1062 - -package machine - -import ( - "device/nxp" - "runtime/interrupt" - "runtime/volatile" -) - -// UART peripheral abstraction layer for the MIMXRT1062 - -type UART struct { - Bus *nxp.LPUART_Type - Buffer *RingBuffer - Interrupt interrupt.Interrupt - - // txBuffer should be allocated globally (such as when UART is created) to - // prevent it being reclaimed or cleaned up prematurely. - txBuffer *RingBuffer - - // these hold the input selector ("daisy chain") values that select which pins - // are connected to the LPUART device, and should be defined where the UART - // instance is declared. see the godoc comments on type muxSelect for more - // details. - muxRX, muxTX muxSelect - - // these are copied from UARTConfig, during (*UART).Configure(UARTConfig), and - // should be considered read-only for internal reference (i.e., modifying them - // will have no desirable effect). - rx, tx Pin - baud uint32 - - // auxiliary state data used internally - configured bool - transmitting volatile.Register32 -} - -func (uart *UART) isTransmitting() bool { return uart.transmitting.Get() != 0 } -func (uart *UART) startTransmitting() { uart.transmitting.Set(1) } -func (uart *UART) stopTransmitting() { uart.transmitting.Set(0) } -func (uart *UART) resetTransmitting() { - uart.stopTransmitting() - uart.Bus.GLOBAL.SetBits(nxp.LPUART_GLOBAL_RST) - uart.Bus.GLOBAL.ClearBits(nxp.LPUART_GLOBAL_RST) -} - -// Configure initializes a UART with the given UARTConfig and other default -// settings. -func (uart *UART) Configure(config UARTConfig) { - - const defaultUartFreq = 115200 - - // use default baud rate if not specified - if config.BaudRate == 0 { - config.BaudRate = defaultUartFreq - } - - // use default UART pins if not specified - if config.RX == 0 && config.TX == 0 { - config.RX = UART_RX_PIN - config.TX = UART_TX_PIN - } - - uart.baud = config.BaudRate - uart.rx = config.RX - uart.tx = config.TX - - // configure the mux and pad control registers - uart.rx.Configure(PinConfig{Mode: PinModeUARTRX}) - uart.tx.Configure(PinConfig{Mode: PinModeUARTTX}) - - // configure the mux input selector - uart.muxRX.connect() - uart.muxTX.connect() - - // reset all internal logic and registers - uart.resetTransmitting() - - // disable until we have finished configuring registers - uart.Bus.CTRL.Set(0) - - // determine the baud rate and over-sample divisors - sbr, osr := uart.getBaudRateDivisor(uart.baud) - - // set the baud rate, over-sample configuration, stop bits - baudBits := (((osr - 1) << nxp.LPUART_BAUD_OSR_Pos) & nxp.LPUART_BAUD_OSR_Msk) | - ((sbr << nxp.LPUART_BAUD_SBR_Pos) & nxp.LPUART_BAUD_SBR_Msk) - if osr <= 8 { - // if OSR less than or equal to 8, we must enable sampling on both edges - baudBits |= nxp.LPUART_BAUD_BOTHEDGE - } - uart.Bus.BAUD.Set(baudBits) - uart.Bus.PINCFG.Set(0) // disable triggers - - // configure watermarks, flush and enable TX/RX FIFOs - rxSize, txSize := uart.getFIFOSize() - rxWater := rxSize >> 1 - if rxWater > uint32(nxp.LPUART_FIFO_RXFIFOSIZE_Msk>>nxp.LPUART_FIFO_RXFIFOSIZE_Pos) { - rxWater = uint32(nxp.LPUART_FIFO_RXFIFOSIZE_Msk >> nxp.LPUART_FIFO_RXFIFOSIZE_Pos) - } - txWater := txSize >> 1 - if txWater > uint32(nxp.LPUART_FIFO_TXFIFOSIZE_Msk>>nxp.LPUART_FIFO_TXFIFOSIZE_Pos) { - txWater = uint32(nxp.LPUART_FIFO_TXFIFOSIZE_Msk >> nxp.LPUART_FIFO_TXFIFOSIZE_Pos) - } - uart.Bus.WATER.Set( - ((rxWater << nxp.LPUART_WATER_RXWATER_Pos) & nxp.LPUART_WATER_RXWATER_Msk) | - ((txWater << nxp.LPUART_WATER_TXWATER_Pos) & nxp.LPUART_WATER_TXWATER_Msk)) - uart.Bus.FIFO.SetBits(nxp.LPUART_FIFO_RXFE | nxp.LPUART_FIFO_TXFE | - nxp.LPUART_FIFO_RXFLUSH | nxp.LPUART_FIFO_TXFLUSH) - - // for now we assume some configuration. in particular: - // Data bits -> 8-bit - // Parity bit -> None (parity bit generation disabled) - // Stop bits -> 1 stop bit - // MSB first -> false - // RX idle type -> idle count starts after start bit - // RX idle config -> 1 idle character - // RX RTS enabled -> false - // TX CTS enabled -> false - - // enable transmitter, receiver functions - uart.Bus.CTRL.Set(nxp.LPUART_CTRL_TE | nxp.LPUART_CTRL_RE | - // enable receiver, idle line interrupts - nxp.LPUART_CTRL_RIE | nxp.LPUART_CTRL_ILIE) - - // clear all status flags - uart.Bus.STAT.Set(uart.Bus.STAT.Get()) - - // enable RX interrupt - uart.Interrupt.SetPriority(0xC0) - uart.Interrupt.Enable() - - uart.configured = true -} - -// Disable disables the UART interface. -// -// If any buffered data has not yet been transmitted, Disable waits until -// transmission completes before disabling the interface. The receiver UART's -// interrupt is also disabled, and the RX/TX pins are reconfigured for GPIO -// input (pull-up). -func (uart *UART) Disable() { - - // first ensure the device is enabled - if uart.configured { - - // wait for any buffered data to send - uart.Sync() - - // stop trapping RX interrupts - uart.Interrupt.Disable() - - // reset all internal registers - uart.resetTransmitting() - - // disable RX/TX functions - uart.Bus.CTRL.ClearBits(nxp.LPUART_CTRL_TE | nxp.LPUART_CTRL_RE) - - // put pins back into GPIO mode - uart.rx.Configure(PinConfig{Mode: PinInputPullup}) - uart.tx.Configure(PinConfig{Mode: PinInputPullup}) - } - uart.configured = false -} - -// Sync blocks the calling goroutine until all data in the output buffer has -// been transmitted. -func (uart *UART) Sync() error { - for uart.isTransmitting() { - } - return nil -} - -// WriteByte writes a single byte of data to the UART interface. -func (uart *UART) writeByte(c byte) error { - uart.startTransmitting() - for !uart.txBuffer.Put(c) { - } - uart.Bus.CTRL.SetBits(nxp.LPUART_CTRL_TIE) - return nil -} - -func (uart *UART) flush() {} - -// getBaudRateDivisor finds the greatest over-sampling factor (4..32) and -// corresponding baud rate divisor (1..8191) that best partition a given baud -// rate into equal intervals. -// -// This is an integral (non-floating point) translation of the logic at the -// beginning of: -// -// void HardwareSerial::begin(uint32_t baud, uint16_t format) -// -// (from Teensyduino: cores/teensy4/HardwareSerial.cpp) -// -// We don't want to use floating point here in case it gets called from an ISR -// or very early during system init. -func (uart *UART) getBaudRateDivisor(baudRate uint32) (sbr uint32, osr uint32) { - const clock = 24000000 // UART is muxed to 24 MHz OSC - err := uint32(0xFFFFFFFF) - sbr, osr = 0, 0 - for o := uint32(4); o <= 32; o++ { - s := ((clock*10)/(baudRate*o) + 5) / 10 - if s == 0 { - s = 1 - } - b := clock / (s * o) - var e uint32 - if b > baudRate { - e = b - baudRate - } else { - e = baudRate - b - } - if e <= err { - err = e - osr = o - sbr = s - } - } - return sbr, osr -} - -func (uart *UART) getFIFOSize() (rx, tx uint32) { - fifo := uart.Bus.FIFO.Get() - rx = uint32(1) << ((fifo & nxp.LPUART_FIFO_RXFIFOSIZE_Msk) >> nxp.LPUART_FIFO_RXFIFOSIZE_Pos) - if rx > 1 { - rx <<= 1 - } - tx = uint32(1) << ((fifo & nxp.LPUART_FIFO_TXFIFOSIZE_Msk) >> nxp.LPUART_FIFO_TXFIFOSIZE_Pos) - if tx > 1 { - tx <<= 1 - } - return rx, tx -} - -func (uart *UART) getStatus() uint32 { - return uart.Bus.STAT.Get() | - ((uart.Bus.FIFO.Get() & uint32(nxp.LPUART_FIFO_TXEMPT_Msk|nxp.LPUART_FIFO_RXEMPT_Msk| - nxp.LPUART_FIFO_TXOF_Msk|nxp.LPUART_FIFO_RXUF_Msk)) >> 16) -} - -func (uart *UART) getEnabledInterrupts() uint32 { - return ((uart.Bus.BAUD.Get() & uint32(nxp.LPUART_BAUD_LBKDIE_Msk|nxp.LPUART_BAUD_RXEDGIE_Msk)) >> 8) | - ((uart.Bus.FIFO.Get() & uint32(nxp.LPUART_FIFO_TXOFE_Msk|nxp.LPUART_FIFO_RXUFE_Msk)) >> 8) | - (uart.Bus.CTRL.Get() & uint32(0xFF0C000)) -} - -func (uart *UART) disableInterrupts(mask uint32) { - uart.Bus.BAUD.ClearBits((mask << 8) & uint32(nxp.LPUART_BAUD_LBKDIE_Msk|nxp.LPUART_BAUD_RXEDGIE_Msk)) - uart.Bus.FIFO.Set((uart.Bus.FIFO.Get() & ^uint32(nxp.LPUART_FIFO_TXOF_Msk|nxp.LPUART_FIFO_RXUF_Msk)) & - ^uint32((mask<<8)&(nxp.LPUART_FIFO_TXOFE_Msk|nxp.LPUART_FIFO_RXUFE_Msk))) - mask &= uint32(0xFFFFFF00) - uart.Bus.CTRL.ClearBits(mask) -} - -func (uart *UART) handleInterrupt(interrupt.Interrupt) { - - stat := uart.getStatus() - inte := uart.getEnabledInterrupts() - - _, txSize := uart.getFIFOSize() - - // check for and clear overrun, otherwise RX will not work - if (stat & uint32(nxp.LPUART_STAT_OR)) != 0 { - uart.Bus.STAT.Set((uart.Bus.STAT.Get() & uint32(0x3FE00000)) | nxp.LPUART_STAT_OR) - } - - // idle or receive data register is full - if (stat & uint32(nxp.LPUART_STAT_RDRF|nxp.LPUART_STAT_IDLE)) != 0 { - count := (uart.Bus.WATER.Get() & uint32(nxp.LPUART_WATER_RXCOUNT_Msk)) >> nxp.LPUART_WATER_RXCOUNT_Pos - for ; count > 0; count-- { - // read up to 8 bits of data at a time - // TODO: 7, 9, and 10-bit support? - uart.Buffer.Put(uint8(uart.Bus.DATA.Get() & uint32(0xFF))) - } - // if it was an IDLE status, clear the flag - if (stat & uint32(nxp.LPUART_STAT_IDLE)) != 0 { - uart.Bus.STAT.SetBits(nxp.LPUART_STAT_IDLE) - } - // disable idle line interrupts - uart.disableInterrupts(nxp.LPUART_CTRL_RIE | nxp.LPUART_CTRL_ORIE) - } - - // check if we have data to write - if ((inte & nxp.LPUART_CTRL_TIE) != 0) && ((stat & nxp.LPUART_STAT_TDRE) != 0) { - for ((uart.Bus.WATER.Get() & uint32(nxp.LPUART_WATER_TXCOUNT_Msk)) >> nxp.LPUART_WATER_TXCOUNT_Pos) < txSize { - if b, ok := uart.txBuffer.Get(); ok { - uart.Bus.DATA.Set(uint32(b)) - } else { - break - } - } - if uart.Bus.STAT.HasBits(nxp.LPUART_STAT_TDRE) { - uart.Bus.CTRL.Set((uart.Bus.CTRL.Get() & ^uint32(nxp.LPUART_CTRL_TIE)) | nxp.LPUART_CTRL_TCIE) - } - } - - if ((inte & nxp.LPUART_CTRL_TCIE) != 0) && ((stat & nxp.LPUART_STAT_TC) != 0) { - uart.stopTransmitting() - uart.Bus.CTRL.ClearBits(nxp.LPUART_CTRL_TCIE) - } -} diff --git a/emb/machine/machine_nrf.go b/emb/machine/machine_nrf.go deleted file mode 100644 index d6d6349..0000000 --- a/emb/machine/machine_nrf.go +++ /dev/null @@ -1,449 +0,0 @@ -//go:build nrf - -package machine - -import ( - "device/nrf" - "internal/binary" - "runtime/interrupt" - "unsafe" -) - -const deviceName = nrf.Device - -var deviceID [8]byte - -// DeviceID returns an identifier that is unique within -// a particular chipset. -// -// The identity is one burnt into the MCU itself, or the -// flash chip at time of manufacture. -// -// It's possible that two different vendors may allocate -// the same DeviceID, so callers should take this into -// account if needing to generate a globally unique id. -// -// The length of the hardware ID is vendor-specific, but -// 8 bytes (64 bits) is common. -func DeviceID() []byte { - words := make([]uint32, 2) - words[0] = nrf.FICR.DEVICEID[0].Get() - words[1] = nrf.FICR.DEVICEID[1].Get() - - for i := 0; i < 8; i++ { - shift := (i % 4) * 8 - w := i / 4 - deviceID[i] = byte(words[w] >> shift) - } - - return deviceID[:] -} - -const ( - PinInput PinMode = (nrf.GPIO_PIN_CNF_DIR_Input << nrf.GPIO_PIN_CNF_DIR_Pos) | (nrf.GPIO_PIN_CNF_INPUT_Connect << nrf.GPIO_PIN_CNF_INPUT_Pos) - PinInputPullup PinMode = PinInput | (nrf.GPIO_PIN_CNF_PULL_Pullup << nrf.GPIO_PIN_CNF_PULL_Pos) - PinInputPulldown PinMode = PinInput | (nrf.GPIO_PIN_CNF_PULL_Pulldown << nrf.GPIO_PIN_CNF_PULL_Pos) - PinOutput PinMode = (nrf.GPIO_PIN_CNF_DIR_Output << nrf.GPIO_PIN_CNF_DIR_Pos) | (nrf.GPIO_PIN_CNF_INPUT_Connect << nrf.GPIO_PIN_CNF_INPUT_Pos) -) - -type PinChange uint8 - -// Pin change interrupt constants for SetInterrupt. -const ( - PinRising PinChange = nrf.GPIOTE_CONFIG_POLARITY_LoToHi - PinFalling PinChange = nrf.GPIOTE_CONFIG_POLARITY_HiToLo - PinToggle PinChange = nrf.GPIOTE_CONFIG_POLARITY_Toggle -) - -// Callbacks to be called for pins configured with SetInterrupt. -var pinCallbacks [len(nrf.GPIOTE.CONFIG)]func(Pin) - -// Configure this pin with the given configuration. -func (p Pin) Configure(config PinConfig) { - cfg := config.Mode | nrf.GPIO_PIN_CNF_DRIVE_S0S1 | nrf.GPIO_PIN_CNF_SENSE_Disabled - port, pin := p.getPortPin() - port.PIN_CNF[pin].Set(uint32(cfg)) -} - -// Set the pin to high or low. -// Warning: only use this on an output pin! -func (p Pin) Set(high bool) { - port, pin := p.getPortPin() - if high { - port.OUTSET.Set(1 << pin) - } else { - port.OUTCLR.Set(1 << pin) - } -} - -// Return the register and mask to enable a given GPIO pin. This can be used to -// implement bit-banged drivers. -func (p Pin) PortMaskSet() (*uint32, uint32) { - port, pin := p.getPortPin() - return &port.OUTSET.Reg, 1 << pin -} - -// Return the register and mask to disable a given port. This can be used to -// implement bit-banged drivers. -func (p Pin) PortMaskClear() (*uint32, uint32) { - port, pin := p.getPortPin() - return &port.OUTCLR.Reg, 1 << pin -} - -// Get returns the current value of a GPIO pin when the pin is configured as an -// input or as an output. -func (p Pin) Get() bool { - port, pin := p.getPortPin() - return (port.IN.Get()>>pin)&1 != 0 -} - -// SetInterrupt sets an interrupt to be executed when a particular pin changes -// state. The pin should already be configured as an input, including a pull up -// or down if no external pull is provided. -// -// This call will replace a previously set callback on this pin. You can pass a -// nil func to unset the pin change interrupt. If you do so, the change -// parameter is ignored and can be set to any value (such as 0). -func (p Pin) SetInterrupt(change PinChange, callback func(Pin)) error { - // Some variables to easily check whether a channel was already configured - // as an event channel for the given pin. - // This is not just an optimization, this is required: the datasheet says - // that configuring more than one channel for a given pin results in - // unpredictable behavior. - expectedConfigMask := uint32(nrf.GPIOTE_CONFIG_MODE_Msk | nrf.GPIOTE_CONFIG_PSEL_Msk) - expectedConfig := nrf.GPIOTE_CONFIG_MODE_Event<> nrf.GPIOTE_CONFIG_PSEL_Pos) - pinCallbacks[i](pin) - } - } - }).Enable() - - // Everything was configured correctly. - return nil -} - -// UART on the NRF. -type UART struct { - Buffer *RingBuffer -} - -// UART -var ( - // UART0 is the hardware UART on the NRF SoC. - _UART0 = UART{Buffer: NewRingBuffer()} - UART0 = &_UART0 -) - -// Configure the UART. -func (uart *UART) Configure(config UARTConfig) { - // Default baud rate to 115200. - if config.BaudRate == 0 { - config.BaudRate = 115200 - } - - uart.SetBaudRate(config.BaudRate) - - // Set TX and RX pins - if config.TX == 0 && config.RX == 0 { - // Use default pins - uart.setPins(UART_TX_PIN, UART_RX_PIN) - } else { - uart.setPins(config.TX, config.RX) - } - - nrf.UART0.ENABLE.Set(nrf.UART_ENABLE_ENABLE_Enabled) - nrf.UART0.TASKS_STARTTX.Set(1) - nrf.UART0.TASKS_STARTRX.Set(1) - nrf.UART0.INTENSET.Set(nrf.UART_INTENSET_RXDRDY_Msk) - - // Enable RX IRQ. - intr := interrupt.New(nrf.IRQ_UART0, _UART0.handleInterrupt) - intr.SetPriority(0xc0) // low priority - intr.Enable() -} - -// SetBaudRate sets the communication speed for the UART. -func (uart *UART) SetBaudRate(br uint32) { - // Magic: calculate 'baudrate' register from the input number. - // Every value listed in the datasheet will be converted to the - // correct register value, except for 192600. I suspect the value - // listed in the nrf52 datasheet (0x0EBED000) is incorrectly rounded - // and should be 0x0EBEE000, as the nrf51 datasheet lists the - // nonrounded value 0x0EBEDFA4. - // Some background: - // https://devzone.nordicsemi.com/f/nordic-q-a/391/uart-baudrate-register-values/2046#2046 - rate := uint32((uint64(br/400)*uint64(400*0xffffffff/16000000) + 0x800) & 0xffffff000) - - nrf.UART0.BAUDRATE.Set(rate) -} - -// WriteByte writes a byte of data to the UART. -func (uart *UART) writeByte(c byte) error { - nrf.UART0.EVENTS_TXDRDY.Set(0) - nrf.UART0.TXD.Set(uint32(c)) - for nrf.UART0.EVENTS_TXDRDY.Get() == 0 { - } - return nil -} - -func (uart *UART) flush() {} - -func (uart *UART) handleInterrupt(interrupt.Interrupt) { - if nrf.UART0.EVENTS_RXDRDY.Get() != 0 { - uart.Receive(byte(nrf.UART0.RXD.Get())) - nrf.UART0.EVENTS_RXDRDY.Set(0x0) - } -} - -const i2cTimeout = 0xffff // this is around 29ms on a nrf52 - -// I2CConfig is used to store config info for I2C. -type I2CConfig struct { - Frequency uint32 - SCL Pin - SDA Pin - Mode I2CMode -} - -// Configure is intended to setup the I2C interface. -func (i2c *I2C) Configure(config I2CConfig) error { - - i2c.disable() - - // Default I2C bus speed is 100 kHz. - if config.Frequency == 0 { - config.Frequency = 100 * KHz - } - // Default I2C pins if not set. - if config.SDA == 0 && config.SCL == 0 { - config.SDA = SDA_PIN - config.SCL = SCL_PIN - } - - // do config - sclPort, sclPin := config.SCL.getPortPin() - sclPort.PIN_CNF[sclPin].Set((nrf.GPIO_PIN_CNF_DIR_Input << nrf.GPIO_PIN_CNF_DIR_Pos) | - (nrf.GPIO_PIN_CNF_INPUT_Connect << nrf.GPIO_PIN_CNF_INPUT_Pos) | - (nrf.GPIO_PIN_CNF_PULL_Pullup << nrf.GPIO_PIN_CNF_PULL_Pos) | - (nrf.GPIO_PIN_CNF_DRIVE_S0D1 << nrf.GPIO_PIN_CNF_DRIVE_Pos) | - (nrf.GPIO_PIN_CNF_SENSE_Disabled << nrf.GPIO_PIN_CNF_SENSE_Pos)) - - sdaPort, sdaPin := config.SDA.getPortPin() - sdaPort.PIN_CNF[sdaPin].Set((nrf.GPIO_PIN_CNF_DIR_Input << nrf.GPIO_PIN_CNF_DIR_Pos) | - (nrf.GPIO_PIN_CNF_INPUT_Connect << nrf.GPIO_PIN_CNF_INPUT_Pos) | - (nrf.GPIO_PIN_CNF_PULL_Pullup << nrf.GPIO_PIN_CNF_PULL_Pos) | - (nrf.GPIO_PIN_CNF_DRIVE_S0D1 << nrf.GPIO_PIN_CNF_DRIVE_Pos) | - (nrf.GPIO_PIN_CNF_SENSE_Disabled << nrf.GPIO_PIN_CNF_SENSE_Pos)) - - i2c.setPins(config.SCL, config.SDA) - - i2c.mode = config.Mode - if i2c.mode == I2CModeController { - i2c.SetBaudRate(config.Frequency) - - i2c.enableAsController() - } else { - i2c.enableAsTarget() - } - - return nil -} - -// SetBaudRate sets the I2C frequency. It has the side effect of also -// enabling the I2C hardware if disabled beforehand. -// -//go:inline -func (i2c *I2C) SetBaudRate(br uint32) error { - switch { - case br >= 400*KHz: - i2c.Bus.SetFREQUENCY(nrf.TWI_FREQUENCY_FREQUENCY_K400) - case br >= 250*KHz: - i2c.Bus.SetFREQUENCY(nrf.TWI_FREQUENCY_FREQUENCY_K250) - default: - i2c.Bus.SetFREQUENCY(nrf.TWI_FREQUENCY_FREQUENCY_K100) - } - - return nil -} - -// signalStop sends a stop signal to the I2C peripheral and waits for confirmation. -func (i2c *I2C) signalStop() error { - tries := 0 - i2c.Bus.TASKS_STOP.Set(1) - for i2c.Bus.EVENTS_STOPPED.Get() == 0 { - tries++ - if tries >= i2cTimeout { - return errI2CSignalStopTimeout - } - } - i2c.Bus.EVENTS_STOPPED.Set(0) - return nil -} - -var rngStarted = false - -// getRNG returns 32 bits of non-deterministic random data based on internal thermal noise. -// According to Nordic's documentation, the random output is suitable for cryptographic purposes. -func getRNG() (ret uint32, err error) { - // There's no apparent way to check the status of the RNG peripheral's task, so simply start it - // to avoid deadlocking while waiting for output. - if !rngStarted { - nrf.RNG.TASKS_START.Set(1) - nrf.RNG.SetCONFIG_DERCEN(nrf.RNG_CONFIG_DERCEN_Enabled) - rngStarted = true - } - - // The RNG returns one byte at a time, so stack up four bytes into a single uint32 for return. - for i := 0; i < 4; i++ { - // Wait for data to be ready. - for nrf.RNG.EVENTS_VALRDY.Get() == 0 { - } - // Append random byte to output. - ret = (ret << 8) ^ nrf.RNG.GetVALUE() - // Unset the EVENTS_VALRDY register to avoid reading the same random output twice. - nrf.RNG.EVENTS_VALRDY.Set(0) - } - - return ret, nil -} - -// ReadTemperature reads the silicon die temperature of the chip. The return -// value is in milli-celsius. -func ReadTemperature() int32 { - nrf.TEMP.TASKS_START.Set(1) - for nrf.TEMP.EVENTS_DATARDY.Get() == 0 { - } - temp := int32(nrf.TEMP.TEMP.Get()) * 250 // the returned value is in units of 0.25°C - nrf.TEMP.EVENTS_DATARDY.Set(0) - return temp -} - -const memoryStart = 0x0 - -// compile-time check for ensuring we fulfill BlockDevice interface -var _ BlockDevice = flashBlockDevice{} - -var Flash flashBlockDevice - -type flashBlockDevice struct { -} - -// ReadAt reads the given number of bytes from the block device. -func (f flashBlockDevice) ReadAt(p []byte, off int64) (n int, err error) { - if FlashDataStart()+uintptr(off)+uintptr(len(p)) > FlashDataEnd() { - return 0, errFlashCannotReadPastEOF - } - - data := unsafe.Slice((*byte)(unsafe.Pointer(FlashDataStart()+uintptr(off))), len(p)) - copy(p, data) - - return len(p), nil -} - -// WriteAt writes the given number of bytes to the block device. -// Only double-word (64 bits) length data can be programmed. See rm0461 page 78. -// If the length of p is not long enough it will be padded with 0xFF bytes. -// This method assumes that the destination is already erased. -func (f flashBlockDevice) WriteAt(p []byte, off int64) (n int, err error) { - if FlashDataStart()+uintptr(off)+uintptr(len(p)) > FlashDataEnd() { - return 0, errFlashCannotWritePastEOF - } - - address := FlashDataStart() + uintptr(off) - padded := flashPad(p, int(f.WriteBlockSize())) - - waitWhileFlashBusy() - - nrf.NVMC.SetCONFIG_WEN(nrf.NVMC_CONFIG_WEN_Wen) - defer nrf.NVMC.SetCONFIG_WEN(nrf.NVMC_CONFIG_WEN_Ren) - - for j := 0; j < len(padded); j += int(f.WriteBlockSize()) { - // write word - *(*uint32)(unsafe.Pointer(address)) = binary.LittleEndian.Uint32(padded[j : j+int(f.WriteBlockSize())]) - address += uintptr(f.WriteBlockSize()) - waitWhileFlashBusy() - } - - return len(padded), nil -} - -// Size returns the number of bytes in this block device. -func (f flashBlockDevice) Size() int64 { - return int64(FlashDataEnd() - FlashDataStart()) -} - -const writeBlockSize = 4 - -// WriteBlockSize returns the block size in which data can be written to -// memory. It can be used by a client to optimize writes, non-aligned writes -// should always work correctly. -func (f flashBlockDevice) WriteBlockSize() int64 { - return writeBlockSize -} - -// EraseBlockSize returns the smallest erasable area on this particular chip -// in bytes. This is used for the block size in EraseBlocks. -// It must be a power of two, and may be as small as 1. A typical size is 4096. -func (f flashBlockDevice) EraseBlockSize() int64 { - return eraseBlockSize() -} - -// EraseBlocks erases the given number of blocks. An implementation may -// transparently coalesce ranges of blocks into larger bundles if the chip -// supports this. The start and len parameters are in block numbers, use -// EraseBlockSize to map addresses to blocks. -func (f flashBlockDevice) EraseBlocks(start, len int64) error { - address := FlashDataStart() + uintptr(start*f.EraseBlockSize()) - waitWhileFlashBusy() - - nrf.NVMC.SetCONFIG_WEN(nrf.NVMC_CONFIG_WEN_Een) - defer nrf.NVMC.SetCONFIG_WEN(nrf.NVMC_CONFIG_WEN_Ren) - - for i := start; i < start+len; i++ { - nrf.NVMC.ERASEPAGE.Set(uint32(address)) - waitWhileFlashBusy() - address += uintptr(f.EraseBlockSize()) - } - - return nil -} - -func waitWhileFlashBusy() { - for nrf.NVMC.GetREADY() != nrf.NVMC_READY_READY_Ready { - } -} diff --git a/emb/machine/machine_nrf51.go b/emb/machine/machine_nrf51.go deleted file mode 100644 index d627d63..0000000 --- a/emb/machine/machine_nrf51.go +++ /dev/null @@ -1,278 +0,0 @@ -//go:build nrf51 - -package machine - -import ( - "device/nrf" -) - -const eraseBlockSizeValue = 1024 - -func eraseBlockSize() int64 { - return eraseBlockSizeValue -} - -// Get peripheral and pin number for this GPIO pin. -func (p Pin) getPortPin() (*nrf.GPIO_Type, uint32) { - return nrf.GPIO, uint32(p) -} - -func (uart *UART) setPins(tx, rx Pin) { - nrf.UART0.PSELTXD.Set(uint32(tx)) - nrf.UART0.PSELRXD.Set(uint32(rx)) -} - -func (i2c *I2C) setPins(scl, sda Pin) { - i2c.Bus.PSELSCL.Set(uint32(scl)) - i2c.Bus.PSELSDA.Set(uint32(sda)) -} - -// SPI on the NRF. -type SPI struct { - Bus *nrf.SPI_Type -} - -// There are 2 SPI interfaces on the NRF51. -var ( - SPI0 = &SPI{Bus: nrf.SPI0} - SPI1 = &SPI{Bus: nrf.SPI1} -) - -// SPIConfig is used to store config info for SPI. -type SPIConfig struct { - Frequency uint32 - SCK Pin - SDO Pin - SDI Pin - LSBFirst bool - Mode uint8 -} - -// Configure is intended to setup the SPI interface. -func (spi *SPI) Configure(config SPIConfig) error { - // Disable bus to configure it - spi.Bus.ENABLE.Set(nrf.SPI_ENABLE_ENABLE_Disabled) - - // set frequency - var freq uint32 - - if config.Frequency == 0 { - config.Frequency = 4000000 // 4MHz - } - - switch { - case config.Frequency >= 8000000: - freq = nrf.SPI_FREQUENCY_FREQUENCY_M8 - case config.Frequency >= 4000000: - freq = nrf.SPI_FREQUENCY_FREQUENCY_M4 - case config.Frequency >= 2000000: - freq = nrf.SPI_FREQUENCY_FREQUENCY_M2 - case config.Frequency >= 1000000: - freq = nrf.SPI_FREQUENCY_FREQUENCY_M1 - case config.Frequency >= 500000: - freq = nrf.SPI_FREQUENCY_FREQUENCY_K500 - case config.Frequency >= 250000: - freq = nrf.SPI_FREQUENCY_FREQUENCY_K250 - default: // below 250kHz, default to the lowest speed available - freq = nrf.SPI_FREQUENCY_FREQUENCY_K125 - } - spi.Bus.FREQUENCY.Set(freq) - - var conf uint32 - - // set bit transfer order - if config.LSBFirst { - conf = (nrf.SPI_CONFIG_ORDER_LsbFirst << nrf.SPI_CONFIG_ORDER_Pos) - } - - // set mode - switch config.Mode { - case 0: - conf &^= (nrf.SPI_CONFIG_CPOL_ActiveHigh << nrf.SPI_CONFIG_CPOL_Pos) - conf &^= (nrf.SPI_CONFIG_CPHA_Leading << nrf.SPI_CONFIG_CPHA_Pos) - case 1: - conf &^= (nrf.SPI_CONFIG_CPOL_ActiveHigh << nrf.SPI_CONFIG_CPOL_Pos) - conf |= (nrf.SPI_CONFIG_CPHA_Trailing << nrf.SPI_CONFIG_CPHA_Pos) - case 2: - conf |= (nrf.SPI_CONFIG_CPOL_ActiveLow << nrf.SPI_CONFIG_CPOL_Pos) - conf &^= (nrf.SPI_CONFIG_CPHA_Leading << nrf.SPI_CONFIG_CPHA_Pos) - case 3: - conf |= (nrf.SPI_CONFIG_CPOL_ActiveLow << nrf.SPI_CONFIG_CPOL_Pos) - conf |= (nrf.SPI_CONFIG_CPHA_Trailing << nrf.SPI_CONFIG_CPHA_Pos) - default: // to mode - conf &^= (nrf.SPI_CONFIG_CPOL_ActiveHigh << nrf.SPI_CONFIG_CPOL_Pos) - conf &^= (nrf.SPI_CONFIG_CPHA_Leading << nrf.SPI_CONFIG_CPHA_Pos) - } - spi.Bus.CONFIG.Set(conf) - - // set pins - if config.SCK == 0 && config.SDO == 0 && config.SDI == 0 { - config.SCK = SPI0_SCK_PIN - config.SDO = SPI0_SDO_PIN - config.SDI = SPI0_SDI_PIN - } - spi.Bus.PSELSCK.Set(uint32(config.SCK)) - spi.Bus.PSELMOSI.Set(uint32(config.SDO)) - spi.Bus.PSELMISO.Set(uint32(config.SDI)) - - // Re-enable bus now that it is configured. - spi.Bus.ENABLE.Set(nrf.SPI_ENABLE_ENABLE_Enabled) - - return nil -} - -// Transfer writes/reads a single byte using the SPI interface. -func (spi *SPI) Transfer(w byte) (byte, error) { - spi.Bus.TXD.Set(uint32(w)) - for spi.Bus.EVENTS_READY.Get() == 0 { - } - r := spi.Bus.RXD.Get() - spi.Bus.EVENTS_READY.Set(0) - - // TODO: handle SPI errors - return byte(r), nil -} - -// Tx handles read/write operation for SPI interface. Since SPI is a synchronous write/read -// interface, there must always be the same number of bytes written as bytes read. -// The Tx method knows about this, and offers a few different ways of calling it. -// -// This form sends the bytes in tx buffer, putting the resulting bytes read into the rx buffer. -// Note that the tx and rx buffers must be the same size: -// -// spi.Tx(tx, rx) -// -// This form sends the tx buffer, ignoring the result. Useful for sending "commands" that return zeros -// until all the bytes in the command packet have been received: -// -// spi.Tx(tx, nil) -// -// This form sends zeros, putting the result into the rx buffer. Good for reading a "result packet": -// -// spi.Tx(nil, rx) -func (spi *SPI) Tx(w, r []byte) error { - var err error - - switch { - case len(w) == 0: - // read only, so write zero and read a result. - for i := range r { - r[i], err = spi.Transfer(0) - if err != nil { - return err - } - } - case len(r) == 0: - // write only - spi.Bus.TXD.Set(uint32(w[0])) - w = w[1:] - for _, b := range w { - spi.Bus.TXD.Set(uint32(b)) - for spi.Bus.EVENTS_READY.Get() == 0 { - } - spi.Bus.EVENTS_READY.Set(0) - _ = spi.Bus.RXD.Get() - } - for spi.Bus.EVENTS_READY.Get() == 0 { - } - spi.Bus.EVENTS_READY.Set(0) - _ = spi.Bus.RXD.Get() - - default: - // write/read - if len(w) != len(r) { - return ErrTxInvalidSliceSize - } - - for i, b := range w { - r[i], err = spi.Transfer(b) - if err != nil { - return err - } - } - } - - return nil -} - -// InitADC initializes the registers needed for ADC. -func InitADC() { - return // no specific setup on nrf51 machine. -} - -// Configure configures an ADC pin to be able to read analog data. -func (a ADC) Configure(ADCConfig) { - return // no pin specific setup on nrf51 machine. -} - -// Get returns the current value of a ADC pin in the range 0..0xffff. -func (a ADC) Get() uint16 { - var value uint32 - - adcPin := a.getADCPin() - - // Enable ADC. - nrf.ADC.SetENABLE(nrf.ADC_ENABLE_ENABLE_Enabled) - - // Set pin to read. - nrf.ADC.SetCONFIG_PSEL(adcPin) - - // config ADC - nrf.ADC.SetCONFIG_RES(nrf.ADC_CONFIG_RES_10bit) - nrf.ADC.SetCONFIG_INPSEL(nrf.ADC_CONFIG_INPSEL_AnalogInputOneThirdPrescaling) - nrf.ADC.SetCONFIG_REFSEL(nrf.ADC_CONFIG_REFSEL_SupplyOneThirdPrescaling) - - // Start tasks. - nrf.ADC.TASKS_START.Set(1) - - // Wait until the sample task is done. - for nrf.ADC.EVENTS_END.Get() == 0 { - } - nrf.ADC.EVENTS_END.Set(0x00) - - value = nrf.ADC.GetRESULT() - - // Stop the ADC - nrf.ADC.TASKS_STOP.Set(1) - - // Disable ADC. - nrf.ADC.SetENABLE(nrf.ADC_ENABLE_ENABLE_Disabled) - - if value < 0 { - value = 0 - } - - // Return 16-bit result from 10-bit value. - return uint16(value << 6) -} - -func (a ADC) getADCPin() uint32 { - switch a.Pin { - case 1: - return nrf.ADC_CONFIG_PSEL_AnalogInput2 - - case 2: - return nrf.ADC_CONFIG_PSEL_AnalogInput3 - - case 3: - return nrf.ADC_CONFIG_PSEL_AnalogInput4 - - case 4: - return nrf.ADC_CONFIG_PSEL_AnalogInput5 - - case 5: - return nrf.ADC_CONFIG_PSEL_AnalogInput6 - - case 6: - return nrf.ADC_CONFIG_PSEL_AnalogInput7 - - case 26: - return nrf.ADC_CONFIG_PSEL_AnalogInput0 - - case 27: - return nrf.ADC_CONFIG_PSEL_AnalogInput1 - - default: - return 0 - } -} diff --git a/emb/machine/machine_nrf52.go b/emb/machine/machine_nrf52.go deleted file mode 100644 index 71c5343..0000000 --- a/emb/machine/machine_nrf52.go +++ /dev/null @@ -1,71 +0,0 @@ -//go:build nrf52 - -package machine - -import ( - "device/nrf" -) - -// Hardware pins -const ( - P0_00 Pin = 0 - P0_01 Pin = 1 - P0_02 Pin = 2 - P0_03 Pin = 3 - P0_04 Pin = 4 - P0_05 Pin = 5 - P0_06 Pin = 6 - P0_07 Pin = 7 - P0_08 Pin = 8 - P0_09 Pin = 9 - P0_10 Pin = 10 - P0_11 Pin = 11 - P0_12 Pin = 12 - P0_13 Pin = 13 - P0_14 Pin = 14 - P0_15 Pin = 15 - P0_16 Pin = 16 - P0_17 Pin = 17 - P0_18 Pin = 18 - P0_19 Pin = 19 - P0_20 Pin = 20 - P0_21 Pin = 21 - P0_22 Pin = 22 - P0_23 Pin = 23 - P0_24 Pin = 24 - P0_25 Pin = 25 - P0_26 Pin = 26 - P0_27 Pin = 27 - P0_28 Pin = 28 - P0_29 Pin = 29 - P0_30 Pin = 30 - P0_31 Pin = 31 -) - -// Get peripheral and pin number for this GPIO pin. -func (p Pin) getPortPin() (*nrf.GPIO_Type, uint32) { - return nrf.P0, uint32(p) -} - -func (uart *UART) setPins(tx, rx Pin) { - nrf.UART0.PSELTXD.Set(uint32(tx)) - nrf.UART0.PSELRXD.Set(uint32(rx)) -} - -func (i2c *I2C) setPins(scl, sda Pin) { - i2c.Bus.PSELSCL.Set(uint32(scl)) - i2c.Bus.PSELSDA.Set(uint32(sda)) -} - -// PWM -var ( - PWM0 = &PWM{PWM: nrf.PWM0} - PWM1 = &PWM{PWM: nrf.PWM1} - PWM2 = &PWM{PWM: nrf.PWM2} -) - -const eraseBlockSizeValue = 4096 - -func eraseBlockSize() int64 { - return eraseBlockSizeValue -} diff --git a/emb/machine/machine_nrf52833.go b/emb/machine/machine_nrf52833.go deleted file mode 100644 index 60558eb..0000000 --- a/emb/machine/machine_nrf52833.go +++ /dev/null @@ -1,92 +0,0 @@ -//go:build nrf52833 - -package machine - -import ( - "device/nrf" -) - -// Hardware pins -const ( - P0_00 Pin = 0 - P0_01 Pin = 1 - P0_02 Pin = 2 - P0_03 Pin = 3 - P0_04 Pin = 4 - P0_05 Pin = 5 - P0_06 Pin = 6 - P0_07 Pin = 7 - P0_08 Pin = 8 - P0_09 Pin = 9 - P0_10 Pin = 10 - P0_11 Pin = 11 - P0_12 Pin = 12 - P0_13 Pin = 13 - P0_14 Pin = 14 - P0_15 Pin = 15 - P0_16 Pin = 16 - P0_17 Pin = 17 - P0_18 Pin = 18 - P0_19 Pin = 19 - P0_20 Pin = 20 - P0_21 Pin = 21 - P0_22 Pin = 22 - P0_23 Pin = 23 - P0_24 Pin = 24 - P0_25 Pin = 25 - P0_26 Pin = 26 - P0_27 Pin = 27 - P0_28 Pin = 28 - P0_29 Pin = 29 - P0_30 Pin = 30 - P0_31 Pin = 31 - P1_00 Pin = 32 - P1_01 Pin = 33 - P1_02 Pin = 34 - P1_03 Pin = 35 - P1_04 Pin = 36 - P1_05 Pin = 37 - P1_06 Pin = 38 - P1_07 Pin = 39 - P1_08 Pin = 40 - P1_09 Pin = 41 - P1_10 Pin = 42 - P1_11 Pin = 43 - P1_12 Pin = 44 - P1_13 Pin = 45 - P1_14 Pin = 46 - P1_15 Pin = 47 -) - -// Get peripheral and pin number for this GPIO pin. -func (p Pin) getPortPin() (*nrf.GPIO_Type, uint32) { - if p >= 32 { - return nrf.P1, uint32(p - 32) - } else { - return nrf.P0, uint32(p) - } -} - -func (uart *UART) setPins(tx, rx Pin) { - nrf.UART0.PSEL.TXD.Set(uint32(tx)) - nrf.UART0.PSEL.RXD.Set(uint32(rx)) -} - -func (i2c *I2C) setPins(scl, sda Pin) { - i2c.Bus.PSEL.SCL.Set(uint32(scl)) - i2c.Bus.PSEL.SDA.Set(uint32(sda)) -} - -// PWM -var ( - PWM0 = &PWM{PWM: nrf.PWM0} - PWM1 = &PWM{PWM: nrf.PWM1} - PWM2 = &PWM{PWM: nrf.PWM2} - PWM3 = &PWM{PWM: nrf.PWM3} -) - -const eraseBlockSizeValue = 4096 - -func eraseBlockSize() int64 { - return eraseBlockSizeValue -} diff --git a/emb/machine/machine_nrf52840.go b/emb/machine/machine_nrf52840.go deleted file mode 100644 index 21a4367..0000000 --- a/emb/machine/machine_nrf52840.go +++ /dev/null @@ -1,110 +0,0 @@ -//go:build nrf52840 - -package machine - -import ( - "device/nrf" - "errors" - "unsafe" -) - -// Get peripheral and pin number for this GPIO pin. -func (p Pin) getPortPin() (*nrf.GPIO_Type, uint32) { - if p >= 32 { - return nrf.P1, uint32(p - 32) - } else { - return nrf.P0, uint32(p) - } -} - -func (uart *UART) setPins(tx, rx Pin) { - nrf.UART0.PSEL.TXD.Set(uint32(tx)) - nrf.UART0.PSEL.RXD.Set(uint32(rx)) -} - -func (i2c *I2C) setPins(scl, sda Pin) { - i2c.Bus.PSEL.SCL.Set(uint32(scl)) - i2c.Bus.PSEL.SDA.Set(uint32(sda)) -} - -// PWM -var ( - PWM0 = &PWM{PWM: nrf.PWM0} - PWM1 = &PWM{PWM: nrf.PWM1} - PWM2 = &PWM{PWM: nrf.PWM2} - PWM3 = &PWM{PWM: nrf.PWM3} -) - -// PDM represents a PDM device -type PDM struct { - device *nrf.PDM_Type - defaultBuffer int16 -} - -// Configure is intended to set up the PDM interface prior to use. -func (pdm *PDM) Configure(config PDMConfig) error { - if config.DIN == 0 { - return errors.New("No DIN pin provided in configuration") - } - - if config.CLK == 0 { - return errors.New("No CLK pin provided in configuration") - } - - config.DIN.Configure(PinConfig{Mode: PinInput}) - config.CLK.Configure(PinConfig{Mode: PinOutput}) - pdm.device = nrf.PDM - pdm.device.PSEL.DIN.Set(uint32(config.DIN)) - pdm.device.PSEL.CLK.Set(uint32(config.CLK)) - pdm.device.PDMCLKCTRL.Set(nrf.PDM_PDMCLKCTRL_FREQ_Default) - pdm.device.RATIO.Set(nrf.PDM_RATIO_RATIO_Ratio64) - pdm.device.GAINL.Set(nrf.PDM_GAINL_GAINL_DefaultGain) - pdm.device.GAINR.Set(nrf.PDM_GAINR_GAINR_DefaultGain) - pdm.device.ENABLE.Set(nrf.PDM_ENABLE_ENABLE_Enabled) - - if config.Stereo { - pdm.device.MODE.Set(nrf.PDM_MODE_OPERATION_Stereo | nrf.PDM_MODE_EDGE_LeftRising) - } else { - pdm.device.MODE.Set(nrf.PDM_MODE_OPERATION_Mono | nrf.PDM_MODE_EDGE_LeftRising) - } - - pdm.device.SAMPLE.SetPTR(uint32(uintptr(unsafe.Pointer(&pdm.defaultBuffer)))) - pdm.device.SAMPLE.SetMAXCNT_BUFFSIZE(1) - pdm.device.SetTASKS_START(1) - return nil -} - -// Read stores a set of samples in the given target buffer. -func (pdm *PDM) Read(buf []int16) (uint32, error) { - pdm.device.SAMPLE.SetPTR(uint32(uintptr(unsafe.Pointer(&buf[0])))) - pdm.device.SAMPLE.MAXCNT.Set(uint32(len(buf))) - pdm.device.EVENTS_STARTED.Set(0) - - // Step 1: wait for new sampling to start for target buffer - for !pdm.device.EVENTS_STARTED.HasBits(nrf.PDM_EVENTS_STARTED_EVENTS_STARTED) { - } - pdm.device.EVENTS_END.Set(0) - - // Step 2: swap out buffers for next recording so we don't continue to - // write to the target buffer - pdm.device.EVENTS_STARTED.Set(0) - pdm.device.SAMPLE.SetPTR(uint32(uintptr(unsafe.Pointer(&pdm.defaultBuffer)))) - pdm.device.SAMPLE.MAXCNT.Set(1) - - // Step 3: wait for original event to end - for pdm.device.EVENTS_END.HasBits(nrf.PDM_EVENTS_STOPPED_EVENTS_STOPPED) { - } - - // Step 4: wait for default buffer to start recording before proceeding - // otherwise we see the contents of target buffer change later - for !pdm.device.EVENTS_STARTED.HasBits(nrf.PDM_EVENTS_STARTED_EVENTS_STARTED) { - } - - return uint32(len(buf)), nil -} - -const eraseBlockSizeValue = 4096 - -func eraseBlockSize() int64 { - return eraseBlockSizeValue -} diff --git a/emb/machine/machine_nrf52840_enter_bootloader.go b/emb/machine/machine_nrf52840_enter_bootloader.go deleted file mode 100644 index d24152a..0000000 --- a/emb/machine/machine_nrf52840_enter_bootloader.go +++ /dev/null @@ -1,38 +0,0 @@ -//go:build nrf52840 - -package machine - -import ( - "device/arm" - "device/nrf" -) - -const ( - dfuMagicSerialOnlyReset = 0x4e - dfuMagicUF2Reset = 0x57 - dfuMagicOTAReset = 0xA8 -) - -// EnterSerialBootloader resets the chip into the serial bootloader. After -// reset, it can be flashed using serial/nrfutil. -func EnterSerialBootloader() { - arm.DisableInterrupts() - nrf.POWER.GPREGRET.Set(dfuMagicSerialOnlyReset) - arm.SystemReset() -} - -// EnterUF2Bootloader resets the chip into the UF2 bootloader. After reset, it -// can be flashed via nrfutil or by copying a UF2 file to the mass storage device -func EnterUF2Bootloader() { - arm.DisableInterrupts() - nrf.POWER.GPREGRET.Set(dfuMagicUF2Reset) - arm.SystemReset() -} - -// EnterOTABootloader resets the chip into the bootloader so that it can be -// flashed via an OTA update -func EnterOTABootloader() { - arm.DisableInterrupts() - nrf.POWER.GPREGRET.Set(dfuMagicOTAReset) - arm.SystemReset() -} diff --git a/emb/machine/machine_nrf52840_lfxtal_false.go b/emb/machine/machine_nrf52840_lfxtal_false.go deleted file mode 100644 index ba38a32..0000000 --- a/emb/machine/machine_nrf52840_lfxtal_false.go +++ /dev/null @@ -1,5 +0,0 @@ -//go:build nrf52840 && nrf52840_lfxtal_false - -package machine - -const HasLowFrequencyCrystal = false diff --git a/emb/machine/machine_nrf52840_lfxtal_true.go b/emb/machine/machine_nrf52840_lfxtal_true.go deleted file mode 100644 index 4bef553..0000000 --- a/emb/machine/machine_nrf52840_lfxtal_true.go +++ /dev/null @@ -1,5 +0,0 @@ -//go:build nrf52840 && ((nrf52840_generic && !nrf52840_lfxtal_false) || nrf52840_lfxtal_true) - -package machine - -const HasLowFrequencyCrystal = true diff --git a/emb/machine/machine_nrf52840_simulator.go b/emb/machine/machine_nrf52840_simulator.go deleted file mode 100644 index f04f05c..0000000 --- a/emb/machine/machine_nrf52840_simulator.go +++ /dev/null @@ -1,60 +0,0 @@ -//go:build !baremetal && (bluemicro840 || circuitplay_bluefruit || clue_alpha || feather_nrf52840_sense || feather_nrf52840 || itsybitsy_nrf52840 || mdbt50qrx || nano_33_ble || nicenano || nrf52840_mdk || particle_3rd_gen || pca10056 || pca10059 || rak4631 || reelboard || xiao_ble) - -// Simulator support for nrf52840 based boards. - -package machine - -// Channel values below are nil, so that they get filled in on the first use. -// This is the same as what happens on baremetal. - -var PWM0 = &timerType{ - instance: 0, - frequency: 16e6, - bits: 15, - prescalers: []int{1, 2, 4, 8, 16, 32, 64, 128}, - channelPins: [][]Pin{ - nil, // channel 0 - nil, // channel 1 - nil, // channel 2 - nil, // channel 3 - }, -} - -var PWM1 = &timerType{ - instance: 1, - frequency: 16e6, - bits: 15, - prescalers: []int{1, 2, 4, 8, 16, 32, 64, 128}, - channelPins: [][]Pin{ - nil, // channel 0 - nil, // channel 1 - nil, // channel 2 - nil, // channel 3 - }, -} - -var PWM2 = &timerType{ - instance: 2, - frequency: 16e6, - bits: 15, - prescalers: []int{1, 2, 4, 8, 16, 32, 64, 128}, - channelPins: [][]Pin{ - nil, // channel 0 - nil, // channel 1 - nil, // channel 2 - nil, // channel 3 - }, -} - -var PWM3 = &timerType{ - instance: 3, - frequency: 16e6, - bits: 15, - prescalers: []int{1, 2, 4, 8, 16, 32, 64, 128}, - channelPins: [][]Pin{ - nil, // channel 0 - nil, // channel 1 - nil, // channel 2 - nil, // channel 3 - }, -} diff --git a/emb/machine/machine_nrf52840_usb.go b/emb/machine/machine_nrf52840_usb.go deleted file mode 100644 index 1fa4694..0000000 --- a/emb/machine/machine_nrf52840_usb.go +++ /dev/null @@ -1,381 +0,0 @@ -//go:build nrf52840 - -package machine - -import ( - "device/arm" - "device/nrf" - "machine/usb" - "runtime/interrupt" - "runtime/volatile" - "unsafe" -) - -const NumberOfUSBEndpoints = 8 - -var ( - sendOnEP0DATADONE struct { - ptr *byte - count int - offset int - } - epinen uint32 - epouten uint32 - easyDMABusy volatile.Register8 - - endPoints = []uint32{ - usb.CONTROL_ENDPOINT: usb.ENDPOINT_TYPE_CONTROL, - usb.CDC_ENDPOINT_ACM: (usb.ENDPOINT_TYPE_INTERRUPT | usb.EndpointIn), - usb.CDC_ENDPOINT_OUT: (usb.ENDPOINT_TYPE_BULK | usb.EndpointOut), - usb.CDC_ENDPOINT_IN: (usb.ENDPOINT_TYPE_BULK | usb.EndpointIn), - usb.HID_ENDPOINT_IN: (usb.ENDPOINT_TYPE_DISABLE), // Interrupt In - usb.HID_ENDPOINT_OUT: (usb.ENDPOINT_TYPE_DISABLE), // Interrupt Out - usb.MIDI_ENDPOINT_IN: (usb.ENDPOINT_TYPE_DISABLE), // Bulk In - usb.MIDI_ENDPOINT_OUT: (usb.ENDPOINT_TYPE_DISABLE), // Bulk Out - } -) - -// enterCriticalSection is used to protect access to easyDMA - only one thing -// can be done with it at a time -func enterCriticalSection() { - waitForEasyDMA() - easyDMABusy.SetBits(1) -} - -func waitForEasyDMA() { - for easyDMABusy.HasBits(1) { - arm.Asm("wfi") - } -} - -func exitCriticalSection() { - easyDMABusy.ClearBits(1) -} - -// Configure the USB peripheral. The config is here for compatibility with the UART interface. -func (dev *USBDevice) Configure(config UARTConfig) { - if dev.initcomplete { - return - } - - state := interrupt.Disable() - defer interrupt.Restore(state) - - nrf.USBD.USBPULLUP.Set(0) - - // Enable IRQ. Make sure this is higher than the SWI2 interrupt handler so - // that it is possible to print to the console from a BLE interrupt. You - // shouldn't generally do that but it is useful for debugging and panic - // logging. - intr := interrupt.New(nrf.IRQ_USBD, handleUSBIRQ) - intr.SetPriority(0x40) // interrupt priority 2 (lower number means more important) - intr.Enable() - - // enable interrupt for end of reset and start of frame - nrf.USBD.INTEN.Set(nrf.USBD_INTENSET_USBEVENT) - - // errata 187 - // https://infocenter.nordicsemi.com/topic/errata_nRF52840_EngB/ERR/nRF52840/EngineeringB/latest/anomaly_840_187.html - (*volatile.Register32)(unsafe.Pointer(uintptr(0x4006EC00))).Set(0x00009375) - (*volatile.Register32)(unsafe.Pointer(uintptr(0x4006ED14))).Set(0x00000003) - (*volatile.Register32)(unsafe.Pointer(uintptr(0x4006EC00))).Set(0x00009375) - - // enable USB - nrf.USBD.ENABLE.Set(1) - - timeout := 300000 - for !nrf.USBD.EVENTCAUSE.HasBits(nrf.USBD_EVENTCAUSE_READY) { - timeout-- - if timeout == 0 { - return - } - } - nrf.USBD.EVENTCAUSE.ClearBits(nrf.USBD_EVENTCAUSE_READY) - - // errata 187 - (*volatile.Register32)(unsafe.Pointer(uintptr(0x4006EC00))).Set(0x00009375) - (*volatile.Register32)(unsafe.Pointer(uintptr(0x4006ED14))).Set(0x00000000) - (*volatile.Register32)(unsafe.Pointer(uintptr(0x4006EC00))).Set(0x00009375) - - dev.initcomplete = true -} - -func handleUSBIRQ(interrupt.Interrupt) { - if nrf.USBD.EVENTS_SOF.Get() == 1 { - nrf.USBD.EVENTS_SOF.Set(0) - - // if you want to blink LED showing traffic, this would be the place... - } - - // USBD ready event - if nrf.USBD.EVENTS_USBEVENT.Get() == 1 { - nrf.USBD.EVENTS_USBEVENT.Set(0) - if (nrf.USBD.EVENTCAUSE.Get() & nrf.USBD_EVENTCAUSE_READY) > 0 { - - // Configure control endpoint - initEndpoint(0, usb.ENDPOINT_TYPE_CONTROL) - nrf.USBD.USBPULLUP.Set(1) - - usbConfiguration = 0 - } - nrf.USBD.EVENTCAUSE.Set(0) - } - - if nrf.USBD.EVENTS_EP0DATADONE.Get() == 1 { - // done sending packet - either need to send another or enter status stage - nrf.USBD.EVENTS_EP0DATADONE.Set(0) - if sendOnEP0DATADONE.ptr != nil { - // previous data was too big for one packet, so send a second - ptr := sendOnEP0DATADONE.ptr - count := sendOnEP0DATADONE.count - if count > usb.EndpointPacketSize { - sendOnEP0DATADONE.offset += usb.EndpointPacketSize - sendOnEP0DATADONE.ptr = &udd_ep_control_cache_buffer[sendOnEP0DATADONE.offset] - count = usb.EndpointPacketSize - } - sendOnEP0DATADONE.count -= count - sendViaEPIn( - 0, - ptr, - count, - ) - - // clear, so we know we're done - if sendOnEP0DATADONE.count == 0 { - sendOnEP0DATADONE.ptr = nil - sendOnEP0DATADONE.offset = 0 - } - } else { - // no more data, so set status stage - SendZlp() // nrf.USBD.TASKS_EP0STATUS.Set(1) - } - return - } - - // Endpoint 0 Setup interrupt - if nrf.USBD.EVENTS_EP0SETUP.Get() == 1 { - // ack setup received - nrf.USBD.EVENTS_EP0SETUP.Set(0) - - // parse setup - setup := parseUSBSetupRegisters() - - ok := false - if (setup.BmRequestType & usb.REQUEST_TYPE) == usb.REQUEST_STANDARD { - // Standard Requests - ok = handleStandardSetup(setup) - } else { - // Class Interface Requests - if setup.WIndex < uint16(len(usbSetupHandler)) && usbSetupHandler[setup.WIndex] != nil { - ok = usbSetupHandler[setup.WIndex](setup) - } - } - - if !ok { - // Stall endpoint - nrf.USBD.TASKS_EP0STALL.Set(1) - } - } - - // Now the actual transfer handlers, ignore endpoint number 0 (setup) - if nrf.USBD.EVENTS_EPDATA.Get() > 0 { - nrf.USBD.EVENTS_EPDATA.Set(0) - epDataStatus := nrf.USBD.EPDATASTATUS.Get() - nrf.USBD.EPDATASTATUS.Set(epDataStatus) - var i uint32 - for i = 1; i < uint32(len(endPoints)); i++ { - // Check if endpoint has a pending interrupt - inDataDone := epDataStatus&(nrf.USBD_EPDATASTATUS_EPIN1<<(i-1)) > 0 - outDataDone := epDataStatus&(nrf.USBD_EPDATASTATUS_EPOUT1<<(i-1)) > 0 - if inDataDone { - if usbTxHandler[i] != nil { - usbTxHandler[i]() - } - } else if outDataDone { - enterCriticalSection() - nrf.USBD.EPOUT[i].PTR.Set(uint32(uintptr(unsafe.Pointer(&udd_ep_out_cache_buffer[i])))) - count := nrf.USBD.SIZE.EPOUT[i].Get() - nrf.USBD.EPOUT[i].MAXCNT.Set(count) - nrf.USBD.TASKS_STARTEPOUT[i].Set(1) - } - } - } - - // ENDEPOUT[n] events - for i := 0; i < len(endPoints); i++ { - if nrf.USBD.EVENTS_ENDEPOUT[i].Get() > 0 { - nrf.USBD.EVENTS_ENDEPOUT[i].Set(0) - buf := handleEndpointRx(uint32(i)) - if usbRxHandler[i] == nil || usbRxHandler[i](buf) { - AckUsbOutTransfer(uint32(i)) - } - exitCriticalSection() - } - } -} - -func parseUSBSetupRegisters() usb.Setup { - return usb.Setup{ - BmRequestType: uint8(nrf.USBD.BMREQUESTTYPE.Get()), - BRequest: uint8(nrf.USBD.BREQUEST.Get()), - WValueL: uint8(nrf.USBD.WVALUEL.Get()), - WValueH: uint8(nrf.USBD.WVALUEH.Get()), - WIndex: uint16((nrf.USBD.WINDEXH.Get() << 8) | nrf.USBD.WINDEXL.Get()), - WLength: uint16(((nrf.USBD.WLENGTHH.Get() & 0xff) << 8) | (nrf.USBD.WLENGTHL.Get() & 0xff)), - } -} - -func initEndpoint(ep, config uint32) { - switch config { - case usb.ENDPOINT_TYPE_INTERRUPT | usb.EndpointIn: - enableEPIn(ep) - - case usb.ENDPOINT_TYPE_BULK | usb.EndpointOut: - nrf.USBD.INTENSET.Set(nrf.USBD_INTENSET_ENDEPOUT0 << ep) - nrf.USBD.SIZE.EPOUT[ep].Set(0) - enableEPOut(ep) - - case usb.ENDPOINT_TYPE_INTERRUPT | usb.EndpointOut: - nrf.USBD.INTENSET.Set(nrf.USBD_INTENSET_ENDEPOUT0 << ep) - nrf.USBD.SIZE.EPOUT[ep].Set(0) - enableEPOut(ep) - - case usb.ENDPOINT_TYPE_BULK | usb.EndpointIn: - enableEPIn(ep) - - case usb.ENDPOINT_TYPE_CONTROL: - enableEPIn(0) - enableEPOut(0) - nrf.USBD.INTENSET.Set(nrf.USBD_INTENSET_ENDEPOUT0 | - nrf.USBD_INTENSET_EP0SETUP | - nrf.USBD_INTENSET_EPDATA | - nrf.USBD_INTENSET_EP0DATADONE) - SendZlp() // nrf.USBD.TASKS_EP0STATUS.Set(1) - } -} - -// SendUSBInPacket sends a packet for USBHID (interrupt in / bulk in). -func SendUSBInPacket(ep uint32, data []byte) bool { - sendUSBPacket(ep, data, 0) - - // clear transfer complete flag - nrf.USBD.INTENCLR.Set(nrf.USBD_INTENCLR_ENDEPOUT0 << 4) - - return true -} - -// Prevent file size increases: https://github.com/tinygo-org/tinygo/pull/998 -// -//go:noinline -func sendUSBPacket(ep uint32, data []byte, maxsize uint16) { - count := len(data) - if 0 < int(maxsize) && int(maxsize) < count { - count = int(maxsize) - } - - if ep == 0 { - copy(udd_ep_control_cache_buffer[:], data[:count]) - if count > usb.EndpointPacketSize { - sendOnEP0DATADONE.offset = usb.EndpointPacketSize - sendOnEP0DATADONE.ptr = &udd_ep_control_cache_buffer[sendOnEP0DATADONE.offset] - sendOnEP0DATADONE.count = count - usb.EndpointPacketSize - count = usb.EndpointPacketSize - } - sendViaEPIn( - ep, - &udd_ep_control_cache_buffer[0], - count, - ) - } else { - copy(udd_ep_in_cache_buffer[ep][:], data[:count]) - sendViaEPIn( - ep, - &udd_ep_in_cache_buffer[ep][0], - count, - ) - } -} - -func handleEndpointRx(ep uint32) []byte { - // get data - count := int(nrf.USBD.EPOUT[ep].AMOUNT.Get()) - - return udd_ep_out_cache_buffer[ep][:count] -} - -// AckUsbOutTransfer is called to acknowledge the completion of a USB OUT transfer. -func AckUsbOutTransfer(ep uint32) { - // set ready for next data - nrf.USBD.SIZE.EPOUT[ep].Set(0) -} - -func SendZlp() { - nrf.USBD.TASKS_EP0STATUS.Set(1) -} - -func sendViaEPIn(ep uint32, ptr *byte, count int) { - nrf.USBD.EPIN[ep].PTR.Set( - uint32(uintptr(unsafe.Pointer(ptr))), - ) - nrf.USBD.EPIN[ep].MAXCNT.Set(uint32(count)) - nrf.USBD.TASKS_STARTEPIN[ep].Set(1) -} - -func enableEPOut(ep uint32) { - epouten = epouten | (nrf.USBD_EPOUTEN_OUT0 << ep) - nrf.USBD.EPOUTEN.Set(epouten) -} - -func enableEPIn(ep uint32) { - epinen = epinen | (nrf.USBD_EPINEN_IN0 << ep) - nrf.USBD.EPINEN.Set(epinen) -} - -func handleUSBSetAddress(setup usb.Setup) bool { - // nrf USBD handles this - return true -} - -func ReceiveUSBControlPacket() ([cdcLineInfoSize]byte, error) { - var b [cdcLineInfoSize]byte - - nrf.USBD.TASKS_EP0RCVOUT.Set(1) - - nrf.USBD.EPOUT[0].PTR.Set(uint32(uintptr(unsafe.Pointer(&udd_ep_out_cache_buffer[0])))) - nrf.USBD.EPOUT[0].MAXCNT.Set(64) - - timeout := 300000 - count := 0 - for { - if nrf.USBD.EVENTS_EP0DATADONE.Get() == 1 { - nrf.USBD.EVENTS_EP0DATADONE.Set(0) - count = int(nrf.USBD.SIZE.EPOUT[0].Get()) - nrf.USBD.TASKS_STARTEPOUT[0].Set(1) - break - } - timeout-- - if timeout == 0 { - return b, ErrUSBReadTimeout - } - } - - timeout = 300000 - for { - if nrf.USBD.EVENTS_ENDEPOUT[0].Get() == 1 { - nrf.USBD.EVENTS_ENDEPOUT[0].Set(0) - break - } - - timeout-- - if timeout == 0 { - return b, ErrUSBReadTimeout - } - } - - nrf.USBD.TASKS_EP0STATUS.Set(1) - nrf.USBD.TASKS_EP0RCVOUT.Set(0) - - copy(b[:7], udd_ep_out_cache_buffer[0][:count]) - - return b, nil -} diff --git a/emb/machine/machine_nrf52840_usb_reset_bossa.go b/emb/machine/machine_nrf52840_usb_reset_bossa.go deleted file mode 100644 index b790eb7..0000000 --- a/emb/machine/machine_nrf52840_usb_reset_bossa.go +++ /dev/null @@ -1,9 +0,0 @@ -//go:build nrf52840 && nrf52840_reset_bossa - -package machine - -// EnterBootloader resets the chip into the serial bootloader. After -// reset, it can be flashed using serial/nrfutil. -func EnterBootloader() { - EnterSerialBootloader() -} diff --git a/emb/machine/machine_nrf52840_usb_reset_none.go b/emb/machine/machine_nrf52840_usb_reset_none.go deleted file mode 100644 index e3900e4..0000000 --- a/emb/machine/machine_nrf52840_usb_reset_none.go +++ /dev/null @@ -1,8 +0,0 @@ -//go:build nrf52840 && !nrf52840_reset_uf2 && !nrf52840_reset_bossa - -package machine - -// EnterBootloader resets the chip into the serial bootloader. -func EnterBootloader() { - // skip -} diff --git a/emb/machine/machine_nrf52840_usb_reset_uf2.go b/emb/machine/machine_nrf52840_usb_reset_uf2.go deleted file mode 100644 index 6573ebb..0000000 --- a/emb/machine/machine_nrf52840_usb_reset_uf2.go +++ /dev/null @@ -1,9 +0,0 @@ -//go:build nrf52840 && nrf52840_reset_uf2 - -package machine - -// EnterBootloader resets the chip into the UF2 bootloader. After reset, it -// can be flashed via nrfutil or by copying a UF2 file to the mass storage device -func EnterBootloader() { - EnterUF2Bootloader() -} diff --git a/emb/machine/machine_nrf528xx.go b/emb/machine/machine_nrf528xx.go deleted file mode 100644 index f8937ae..0000000 --- a/emb/machine/machine_nrf528xx.go +++ /dev/null @@ -1,259 +0,0 @@ -//go:build nrf52840 || nrf52833 - -package machine - -import ( - "device/nrf" - "unsafe" -) - -// I2C on the NRF528xx. -type I2C struct { - Bus *nrf.TWIM_Type // Called Bus to align with Bus field in nrf51 - BusT *nrf.TWIS_Type - mode I2CMode -} - -// There are 2 I2C interfaces on the NRF. -var ( - I2C0 = &I2C{Bus: nrf.TWIM0, BusT: nrf.TWIS0} - I2C1 = &I2C{Bus: nrf.TWIM1, BusT: nrf.TWIS1} -) - -func (i2c *I2C) enableAsController() { - i2c.Bus.ENABLE.Set(nrf.TWIM_ENABLE_ENABLE_Enabled) -} - -func (i2c *I2C) enableAsTarget() { - i2c.BusT.ENABLE.Set(nrf.TWIS_ENABLE_ENABLE_Enabled) -} - -func (i2c *I2C) disable() { - i2c.Bus.ENABLE.Set(0) -} - -// Tx does a single I2C transaction at the specified address (when in controller mode). -// -// 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) (err error) { - i2c.Bus.ADDRESS.Set(uint32(addr)) - - i2c.Bus.EVENTS_STOPPED.Set(0) - i2c.Bus.EVENTS_ERROR.Set(0) - i2c.Bus.EVENTS_RXSTARTED.Set(0) - i2c.Bus.EVENTS_TXSTARTED.Set(0) - i2c.Bus.EVENTS_LASTRX.Set(0) - i2c.Bus.EVENTS_LASTTX.Set(0) - i2c.Bus.EVENTS_SUSPENDED.Set(0) - - // Configure for a single shot to perform both write and read (as applicable) - if len(w) != 0 { - i2c.Bus.TXD.PTR.Set(uint32(uintptr(unsafe.Pointer(&w[0])))) - i2c.Bus.TXD.MAXCNT.Set(uint32(len(w))) - - // If no read, immediately signal stop after TX - if len(r) == 0 { - i2c.Bus.SHORTS.Set(nrf.TWIM_SHORTS_LASTTX_STOP) - } - } - if len(r) != 0 { - i2c.Bus.RXD.PTR.Set(uint32(uintptr(unsafe.Pointer(&r[0])))) - i2c.Bus.RXD.MAXCNT.Set(uint32(len(r))) - - // Auto-start Rx after Tx and Stop after Rx - i2c.Bus.SHORTS.Set(nrf.TWIM_SHORTS_LASTTX_STARTRX | nrf.TWIM_SHORTS_LASTRX_STOP) - } - - // Fire the transaction - i2c.Bus.TASKS_RESUME.Set(1) - if len(w) != 0 { - i2c.Bus.TASKS_STARTTX.Set(1) - } else if len(r) != 0 { - i2c.Bus.TASKS_STARTRX.Set(1) - } - - // Wait until transaction stopped to ensure buffers fully processed - for i2c.Bus.EVENTS_STOPPED.Get() == 0 { - // Allow scheduler to run - gosched() - - // Handle errors by ensuring STOP sent on bus - if i2c.Bus.EVENTS_ERROR.Get() != 0 { - if i2c.Bus.EVENTS_STOPPED.Get() == 0 { - // STOP cannot be sent during SUSPEND - i2c.Bus.TASKS_RESUME.Set(1) - i2c.Bus.TASKS_STOP.Set(1) - } - err = twiCError(i2c.Bus.ERRORSRC.Get()) - } - } - - return -} - -// Listen starts listening for I2C requests sent to specified address -// -// addr is the address to listen to -func (i2c *I2C) Listen(addr uint8) error { - i2c.BusT.ADDRESS[0].Set(uint32(addr)) - i2c.BusT.CONFIG.Set(nrf.TWIS_CONFIG_ADDRESS0_Enabled) - - i2c.BusT.EVENTS_STOPPED.Set(0) - i2c.BusT.EVENTS_ERROR.Set(0) - i2c.BusT.EVENTS_RXSTARTED.Set(0) - i2c.BusT.EVENTS_TXSTARTED.Set(0) - i2c.BusT.EVENTS_WRITE.Set(0) - i2c.BusT.EVENTS_READ.Set(0) - - return nil -} - -// WaitForEvent blocks the current go-routine until an I2C event is received (when in Target mode). -// -// The passed buffer will be populated for receive events, with the number of bytes -// received returned in count. For other event types, buf is not modified and a count -// of zero is returned. -// -// For request events, the caller MUST call `Reply` to avoid hanging the i2c bus indefinitely. -func (i2c *I2C) WaitForEvent(buf []byte) (evt I2CTargetEvent, count int, err error) { - i2c.BusT.RXD.PTR.Set(uint32(uintptr(unsafe.Pointer(&buf[0])))) - i2c.BusT.RXD.MAXCNT.Set(uint32(len(buf))) - - i2c.BusT.TASKS_PREPARERX.Set(nrf.TWIS_TASKS_PREPARERX_TASKS_PREPARERX_Trigger) - - i2c.Bus.TASKS_RESUME.Set(1) - - for i2c.BusT.EVENTS_STOPPED.Get() == 0 && - i2c.BusT.EVENTS_READ.Get() == 0 { - gosched() - - if i2c.BusT.EVENTS_ERROR.Get() != 0 { - i2c.BusT.EVENTS_ERROR.Set(0) - return I2CReceive, 0, twisError(i2c.BusT.ERRORSRC.Get()) - } - } - - count = 0 - evt = I2CFinish - err = nil - - if i2c.BusT.EVENTS_WRITE.Get() != 0 { - i2c.BusT.EVENTS_WRITE.Set(0) - - // Data was sent to this target. We've waited for - // READ or STOPPED event, so transmission should be - // complete. - count = int(i2c.BusT.RXD.AMOUNT.Get()) - evt = I2CReceive - } else if i2c.BusT.EVENTS_READ.Get() != 0 { - i2c.BusT.EVENTS_READ.Set(0) - - // Data is requested from this target, hw will stretch - // the controller's clock until there is a reply to - // send - evt = I2CRequest - } else if i2c.BusT.EVENTS_STOPPED.Get() != 0 { - i2c.BusT.EVENTS_STOPPED.Set(0) - evt = I2CFinish - } - - return -} - -// Reply supplies the response data the controller. -func (i2c *I2C) Reply(buf []byte) error { - i2c.BusT.TXD.PTR.Set(uint32(uintptr(unsafe.Pointer(&buf[0])))) - i2c.BusT.TXD.MAXCNT.Set(uint32(len(buf))) - - i2c.BusT.EVENTS_STOPPED.Set(0) - - // Trigger Tx - i2c.BusT.TASKS_PREPARETX.Set(nrf.TWIS_TASKS_PREPARETX_TASKS_PREPARETX_Trigger) - - // Block, waiting for Tx to complete - for i2c.BusT.EVENTS_STOPPED.Get() == 0 { - gosched() - - if i2c.BusT.EVENTS_ERROR.Get() != 0 { - return twisError(i2c.BusT.ERRORSRC.Get()) - } - } - - i2c.BusT.EVENTS_STOPPED.Set(0) - - return nil -} - -// twiCError converts an I2C controller error to Go -func twiCError(val uint32) error { - if val == 0 { - return nil - } else if val&nrf.TWIM_ERRORSRC_OVERRUN_Msk == nrf.TWIM_ERRORSRC_OVERRUN { - return errI2CBusError - } else if val&nrf.TWIM_ERRORSRC_ANACK_Msk == nrf.TWIM_ERRORSRC_ANACK { - return errI2CAckExpected - } else if val&nrf.TWIM_ERRORSRC_DNACK_Msk == nrf.TWIM_ERRORSRC_DNACK { - return errI2CAckExpected - } - - return errI2CBusError -} - -// twisError converts an I2C target error to Go -func twisError(val uint32) error { - if val == 0 { - return nil - } else if val&nrf.TWIS_ERRORSRC_OVERFLOW_Msk == nrf.TWIS_ERRORSRC_OVERFLOW { - return errI2COverflow - } else if val&nrf.TWIS_ERRORSRC_DNACK_Msk == nrf.TWIS_ERRORSRC_DNACK { - return errI2CAckExpected - } else if val&nrf.TWIS_ERRORSRC_OVERREAD_Msk == nrf.TWIS_ERRORSRC_OVERREAD { - return errI2COverread - } - - return errI2CBusError -} - -var ( - Watchdog = &watchdogImpl{} -) - -const ( - // WatchdogMaxTimeout in milliseconds (approx 36h) - WatchdogMaxTimeout = (0xffffffff * 1000) / 32768 -) - -type watchdogImpl struct { -} - -// Configure the watchdog. -// -// This method should not be called after the watchdog is started and on -// some platforms attempting to reconfigure after starting the watchdog -// is explicitly forbidden / will not work. -func (wd *watchdogImpl) Configure(config WatchdogConfig) error { - // 32.768kHz counter - crv := int32((int64(config.TimeoutMillis) * 32768) / 1000) - nrf.WDT.CRV.Set(uint32(crv)) - - // One source - nrf.WDT.RREN.Set(0x1) - - // Run during sleep - nrf.WDT.CONFIG.Set(nrf.WDT_CONFIG_SLEEP_Run) - - return nil -} - -// Starts the watchdog. -func (wd *watchdogImpl) Start() error { - nrf.WDT.TASKS_START.Set(nrf.WDT_TASKS_START_TASKS_START) - return nil -} - -// Update the watchdog, indicating that `source` is healthy. -func (wd *watchdogImpl) Update() { - // 0x6E524635 = magic value from datasheet - nrf.WDT.RR[0].Set(0x6E524635) -} diff --git a/emb/machine/machine_nrf52xxx.go b/emb/machine/machine_nrf52xxx.go deleted file mode 100644 index a582a7a..0000000 --- a/emb/machine/machine_nrf52xxx.go +++ /dev/null @@ -1,546 +0,0 @@ -//go:build nrf52 || nrf52840 || nrf52833 - -package machine - -import ( - "device/nrf" - "runtime/volatile" - "unsafe" -) - -func CPUFrequency() uint32 { - return 64000000 -} - -// InitADC initializes the registers needed for ADC. -func InitADC() { - // Enable ADC. - // The ADC does not consume a noticeable amount of current by being enabled. - nrf.SAADC.ENABLE.Set(nrf.SAADC_ENABLE_ENABLE_Enabled << nrf.SAADC_ENABLE_ENABLE_Pos) -} - -// Configure configures an ADC pin to be able to read analog data. -// Reference voltage can be 150, 300, 600, 1200, 1800, 2400, 3000(default), 3600 mV -// Resolution can be 8, 10, 12(default), 14 bits -// SampleTime will be ceiled to 3(default), 5, 10, 15, 20 or 40(max) µS respectively -// Samples can be 1(default), 2, 4, 8, 16, 32, 64, 128, 256 samples -func (a *ADC) Configure(config ADCConfig) { - var configVal uint32 = nrf.SAADC_CH_CONFIG_RESP_Bypass<= 8000000: - freq = nrf.SPIM_FREQUENCY_FREQUENCY_M8 - case config.Frequency >= 4000000: - freq = nrf.SPIM_FREQUENCY_FREQUENCY_M4 - case config.Frequency >= 2000000: - freq = nrf.SPIM_FREQUENCY_FREQUENCY_M2 - case config.Frequency >= 1000000: - freq = nrf.SPIM_FREQUENCY_FREQUENCY_M1 - case config.Frequency >= 500000: - freq = nrf.SPIM_FREQUENCY_FREQUENCY_K500 - case config.Frequency >= 250000: - freq = nrf.SPIM_FREQUENCY_FREQUENCY_K250 - default: // below 250kHz, default to the lowest speed available - freq = nrf.SPIM_FREQUENCY_FREQUENCY_K125 - } - spi.Bus.FREQUENCY.Set(freq) - - var conf uint32 - - // set bit transfer order - if config.LSBFirst { - conf = (nrf.SPIM_CONFIG_ORDER_LsbFirst << nrf.SPIM_CONFIG_ORDER_Pos) - } - - // set mode - switch config.Mode { - case 0: - conf &^= (nrf.SPIM_CONFIG_CPOL_ActiveHigh << nrf.SPIM_CONFIG_CPOL_Pos) - conf &^= (nrf.SPIM_CONFIG_CPHA_Leading << nrf.SPIM_CONFIG_CPHA_Pos) - case 1: - conf &^= (nrf.SPIM_CONFIG_CPOL_ActiveHigh << nrf.SPIM_CONFIG_CPOL_Pos) - conf |= (nrf.SPIM_CONFIG_CPHA_Trailing << nrf.SPIM_CONFIG_CPHA_Pos) - case 2: - conf |= (nrf.SPIM_CONFIG_CPOL_ActiveLow << nrf.SPIM_CONFIG_CPOL_Pos) - conf &^= (nrf.SPIM_CONFIG_CPHA_Leading << nrf.SPIM_CONFIG_CPHA_Pos) - case 3: - conf |= (nrf.SPIM_CONFIG_CPOL_ActiveLow << nrf.SPIM_CONFIG_CPOL_Pos) - conf |= (nrf.SPIM_CONFIG_CPHA_Trailing << nrf.SPIM_CONFIG_CPHA_Pos) - default: // to mode - conf &^= (nrf.SPIM_CONFIG_CPOL_ActiveHigh << nrf.SPIM_CONFIG_CPOL_Pos) - conf &^= (nrf.SPIM_CONFIG_CPHA_Leading << nrf.SPIM_CONFIG_CPHA_Pos) - } - spi.Bus.CONFIG.Set(conf) - - // set pins - if config.SCK == 0 && config.SDO == 0 && config.SDI == 0 { - config.SCK = SPI0_SCK_PIN - config.SDO = SPI0_SDO_PIN - config.SDI = SPI0_SDI_PIN - } - spi.Bus.PSEL.SCK.Set(uint32(config.SCK)) - spi.Bus.PSEL.MOSI.Set(uint32(config.SDO)) - spi.Bus.PSEL.MISO.Set(uint32(config.SDI)) - - // Re-enable bus now that it is configured. - spi.Bus.ENABLE.Set(nrf.SPIM_ENABLE_ENABLE_Enabled) - - return nil -} - -// Transfer writes/reads a single byte using the SPI interface. -func (spi *SPI) Transfer(w byte) (byte, error) { - buf := spi.buf[:] - buf[0] = w - err := spi.Tx(buf[:], buf[:]) - return buf[0], err -} - -// Tx handles read/write operation for SPI interface. Since SPI is a synchronous -// write/read interface, there must always be the same number of bytes written -// as bytes read. Therefore, if the number of bytes don't match it will be -// padded until they fit: if len(w) > len(r) the extra bytes received will be -// dropped and if len(w) < len(r) extra 0 bytes will be sent. -func (spi *SPI) Tx(w, r []byte) error { - // Unfortunately the hardware (on the nrf52832) only supports up to 255 - // bytes in the buffers, so if either w or r is longer than that the - // transfer needs to be broken up in pieces. - // The nrf52840 supports far larger buffers however, which isn't yet - // supported. - for len(r) != 0 || len(w) != 0 { - // Prepare the SPI transfer: set the DMA pointers and lengths. - // read buffer - nr := uint32(len(r)) - if nr > 0 { - if nr > 255 { - nr = 255 - } - spi.Bus.RXD.PTR.Set(uint32(uintptr(unsafe.Pointer(&r[0])))) - r = r[nr:] - } - spi.Bus.RXD.MAXCNT.Set(nr) - - // write buffer - nw := uint32(len(w)) - if nw > 0 { - if nw > 255 { - nw = 255 - } - spi.Bus.TXD.PTR.Set(uint32(uintptr(unsafe.Pointer(&w[0])))) - w = w[nw:] - } - spi.Bus.TXD.MAXCNT.Set(nw) - - // Do the transfer. - // Note: this can be improved by not waiting until the transfer is - // finished if the transfer is send-only (a common case). - spi.Bus.TASKS_START.Set(1) - for spi.Bus.EVENTS_END.Get() == 0 { - } - spi.Bus.EVENTS_END.Set(0) - } - - return nil -} - -// PWM is one PWM peripheral, which consists of a counter and multiple output -// channels (that can be connected to actual pins). You can set the frequency -// using SetPeriod, but only for all the channels in this PWM peripheral at -// once. -type PWM struct { - PWM *nrf.PWM_Type - - channelValues [4]volatile.Register16 -} - -// Configure enables and configures this PWM. -// On the nRF52 series, the maximum period is around 0.26s. -func (pwm *PWM) Configure(config PWMConfig) error { - // Enable the peripheral. - pwm.PWM.ENABLE.Set(nrf.PWM_ENABLE_ENABLE_Enabled << nrf.PWM_ENABLE_ENABLE_Pos) - - // Use up counting only. TODO: allow configuring as up-and-down. - pwm.PWM.MODE.Set(nrf.PWM_MODE_UPDOWN_Up << nrf.PWM_MODE_UPDOWN_Pos) - - // Indicate there are four channels that each have a different value. - pwm.PWM.DECODER.Set(nrf.PWM_DECODER_LOAD_Individual< maxTop { - return ErrPWMPeriodTooLong - } - } - pwm.PWM.COUNTERTOP.Set(uint32(top)) - - // Apparently this is needed to apply the new COUNTERTOP. - pwm.PWM.TASKS_SEQSTART[0].Set(1) - - return nil -} - -// Top returns the current counter top, for use in duty cycle calculation. It -// will only change with a call to Configure or SetPeriod, otherwise it is -// constant. -// -// The value returned here is hardware dependent. In general, it's best to treat -// it as an opaque value that can be divided by some number and passed to -// pwm.Set (see pwm.Set for more information). -func (pwm *PWM) Top() uint32 { - return pwm.PWM.COUNTERTOP.Get() -} - -// Channel returns a PWM channel for the given pin. -func (pwm *PWM) Channel(pin Pin) (uint8, error) { - config := uint32(pin) - for ch := uint8(0); ch < 4; ch++ { - channelConfig := pwm.PWM.PSEL.OUT[ch].Get() - if channelConfig == 0xffffffff { - // Unused channel. Configure it. - pwm.PWM.PSEL.OUT[ch].Set(config) - // Configure the pin (required by the reference manual). - pin.Configure(PinConfig{Mode: PinOutput}) - // Set channel to zero and non-inverting. - pwm.channelValues[ch].Set(0x8000) - return ch, nil - } else if channelConfig == config { - // This channel is already configured for this pin. - return ch, nil - } - } - - // All four pins are already in use with other pins. - return 0, ErrInvalidOutputPin -} - -// SetInverting sets whether to invert the output of this channel. -// Without inverting, a 25% duty cycle would mean the output is high for 25% of -// the time and low for the rest. Inverting flips the output as if a NOT gate -// was placed at the output, meaning that the output would be 25% low and 75% -// high with a duty cycle of 25%. -func (pwm *PWM) SetInverting(channel uint8, inverting bool) { - ptr := &pwm.channelValues[channel] - if inverting { - ptr.Set(ptr.Get() &^ 0x8000) - } else { - ptr.Set(ptr.Get() | 0x8000) - } -} - -// Set updates the channel value. This is used to control the channel duty -// cycle. For example, to set it to a 25% duty cycle, use: -// -// ch.Set(ch.Top() / 4) -// -// ch.Set(0) will set the output to low and ch.Set(ch.Top()) will set the output -// to high, assuming the output isn't inverted. -func (pwm *PWM) Set(channel uint8, value uint32) { - // Update the channel value while retaining the polarity bit. - ptr := &pwm.channelValues[channel] - ptr.Set(ptr.Get()&0x8000 | uint16(value)&0x7fff) - - // Start the PWM, if it isn't already running. - pwm.PWM.TASKS_SEQSTART[0].Set(1) -} diff --git a/emb/machine/machine_nrf5x.go b/emb/machine/machine_nrf5x.go deleted file mode 100644 index 4c73103..0000000 --- a/emb/machine/machine_nrf5x.go +++ /dev/null @@ -1,126 +0,0 @@ -//go:build nrf51 || nrf52 - -package machine - -import "device/nrf" - -// I2C on the NRF51 and NRF52. -type I2C struct { - Bus *nrf.TWI_Type - mode I2CMode -} - -// There are 2 I2C interfaces on the NRF. -var ( - I2C0 = &I2C{Bus: nrf.TWI0} - I2C1 = &I2C{Bus: nrf.TWI1} -) - -func (i2c *I2C) enableAsController() { - i2c.Bus.ENABLE.Set(nrf.TWI_ENABLE_ENABLE_Enabled) -} - -func (i2c *I2C) enableAsTarget() { - // Not supported on this hardware -} - -func (i2c *I2C) disable() { - i2c.Bus.ENABLE.Set(0) -} - -// 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) (err error) { - - // Tricky stop condition. - // After reads, the stop condition is generated implicitly with a shortcut. - // After writes not followed by reads and in the case of errors, stop must be generated explicitly. - - i2c.Bus.ADDRESS.Set(uint32(addr)) - - if len(w) != 0 { - i2c.Bus.TASKS_STARTTX.Set(1) // start transmission for writing - for _, b := range w { - if err = i2c.writeByte(b); err != nil { - i2c.signalStop() - return - } - } - } - - if len(r) != 0 { - // To trigger suspend task when a byte is received - i2c.Bus.SHORTS.Set(nrf.TWI_SHORTS_BB_SUSPEND) - i2c.Bus.TASKS_STARTRX.Set(1) // re-start transmission for reading - for i := range r { // read each char - if i+1 == len(r) { - // To trigger stop task when last byte is received, set before resume task. - i2c.Bus.SHORTS.Set(nrf.TWI_SHORTS_BB_STOP) - } - if i > 0 { - i2c.Bus.TASKS_RESUME.Set(1) // re-start transmission for reading - } - if r[i], err = i2c.readByte(); err != nil { - i2c.Bus.SHORTS.Set(nrf.TWI_SHORTS_BB_SUSPEND_Disabled) - i2c.signalStop() - return - } - } - i2c.Bus.SHORTS.Set(nrf.TWI_SHORTS_BB_SUSPEND_Disabled) - } - - if len(r) == 0 { - // Stop the I2C transaction after the write. - err = i2c.signalStop() - } else { - // The last byte read has already stopped the transaction, via - // TWI_SHORTS_BB_STOP. But we still need to wait until we receive the - // STOPPED event. - tries := 0 - for i2c.Bus.EVENTS_STOPPED.Get() == 0 { - tries++ - if tries >= i2cTimeout { - return errI2CSignalStopTimeout - } - } - i2c.Bus.EVENTS_STOPPED.Set(0) - } - - return -} - -// writeByte writes a single byte to the I2C bus and waits for confirmation. -func (i2c *I2C) writeByte(data byte) error { - tries := 0 - i2c.Bus.TXD.Set(uint32(data)) - for i2c.Bus.EVENTS_TXDSENT.Get() == 0 { - if e := i2c.Bus.EVENTS_ERROR.Get(); e != 0 { - i2c.Bus.EVENTS_ERROR.Set(0) - return errI2CBusError - } - tries++ - if tries >= i2cTimeout { - return errI2CWriteTimeout - } - } - i2c.Bus.EVENTS_TXDSENT.Set(0) - return nil -} - -// readByte reads a single byte from the I2C bus when it is ready. -func (i2c *I2C) readByte() (byte, error) { - tries := 0 - for i2c.Bus.EVENTS_RXDREADY.Get() == 0 { - if e := i2c.Bus.EVENTS_ERROR.Get(); e != 0 { - i2c.Bus.EVENTS_ERROR.Set(0) - return 0, errI2CBusError - } - tries++ - if tries >= i2cTimeout { - return 0, errI2CReadTimeout - } - } - i2c.Bus.EVENTS_RXDREADY.Set(0) - return byte(i2c.Bus.RXD.Get()), nil -} diff --git a/emb/machine/machine_nrf_bare.go b/emb/machine/machine_nrf_bare.go deleted file mode 100644 index b94886e..0000000 --- a/emb/machine/machine_nrf_bare.go +++ /dev/null @@ -1,9 +0,0 @@ -//go:build nrf && !softdevice - -package machine - -// GetRNG returns 32 bits of non-deterministic random data based on internal thermal noise. -// According to Nordic's documentation, the random output is suitable for cryptographic purposes. -func GetRNG() (ret uint32, err error) { - return getRNG() -} diff --git a/emb/machine/machine_nrf_sd.go b/emb/machine/machine_nrf_sd.go deleted file mode 100644 index b816e62..0000000 --- a/emb/machine/machine_nrf_sd.go +++ /dev/null @@ -1,59 +0,0 @@ -//go:build nrf && softdevice - -package machine - -import ( - "device/arm" - "device/nrf" - - "errors" -) - -// avoid a heap allocation in GetRNG. -var ( - softdeviceEnabled uint8 - bytesAvailable uint8 - buf [4]uint8 - - errNoSoftDeviceSupport = errors.New("rng: softdevice not supported on this device") - errNotEnoughRandomData = errors.New("rng: not enough random data available") -) - -// GetRNG returns 32 bits of non-deterministic random data based on internal thermal noise. -// According to Nordic's documentation, the random output is suitable for cryptographic purposes. -func GetRNG() (ret uint32, err error) { - // First check whether the SoftDevice is enabled. - // sd_rand_application_bytes_available_get cannot be called when the SoftDevice is not enabled. - arm.SVCall1(0x12, &softdeviceEnabled) // sd_softdevice_is_enabled - - if softdeviceEnabled == 0 { - return getRNG() - } - - // call into the SoftDevice to get random data bytes available - switch nrf.Device { - case "nrf51": - // sd_rand_application_bytes_available_get: SOC_SVC_BASE_NOT_AVAILABLE + 4 - arm.SVCall1(0x2B+4, &bytesAvailable) - case "nrf52", "nrf52840", "nrf52833": - // sd_rand_application_bytes_available_get: SOC_SVC_BASE_NOT_AVAILABLE + 4 - arm.SVCall1(0x2C+4, &bytesAvailable) - default: - return 0, errNoSoftDeviceSupport - } - - if bytesAvailable < 4 { - return 0, errNotEnoughRandomData - } - - switch nrf.Device { - case "nrf51": - // sd_rand_application_vector_get: SOC_SVC_BASE_NOT_AVAILABLE + 5 - arm.SVCall2(0x2B+5, &buf, 4) - case "nrf52", "nrf52840", "nrf52833": - // sd_rand_application_vector_get: SOC_SVC_BASE_NOT_AVAILABLE + 5 - arm.SVCall2(0x2C+5, &buf, 4) - } - - return uint32(buf[0]) | uint32(buf[1])<<8 | uint32(buf[2])<<16 | uint32(buf[3])<<24, nil -} diff --git a/emb/machine/machine_nxpmk66f18.go b/emb/machine/machine_nxpmk66f18.go deleted file mode 100644 index 5dd54d9..0000000 --- a/emb/machine/machine_nxpmk66f18.go +++ /dev/null @@ -1,291 +0,0 @@ -// Derivative work of Teensyduino Core Library -// http://www.pjrc.com/teensy/ -// Copyright (c) 2017 PJRC.COM, LLC. -// -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to -// permit persons to whom the Software is furnished to do so, subject to -// the following conditions: -// -// 1. The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// 2. If the Software is incorporated into a build system that allows -// selection among a list of target devices, then similar target -// devices manufactured by PJRC.COM must be included in the list of -// target devices and selectable in the same manner. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS -// BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. - -//go:build nxp && mk66f18 - -package machine - -import ( - "device/nxp" - "runtime/volatile" - "unsafe" -) - -const deviceName = nxp.Device - -const ( - PinInput PinMode = iota - PinInputPullup - PinInputPulldown - PinOutput - PinOutputOpenDrain - PinDisable -) - -// Deprecated: use PinInputPullup and PinInputPulldown instead. -const ( - PinInputPullUp = PinInputPullup - PinInputPullDown = PinInputPulldown -) - -const ( - PA00 Pin = iota - PA01 - PA02 - PA03 - PA04 - PA05 - PA06 - PA07 - PA08 - PA09 - PA10 - PA11 - PA12 - PA13 - PA14 - PA15 - PA16 - PA17 - PA18 - PA19 - PA20 - PA21 - PA22 - PA23 - PA24 - PA25 - PA26 - PA27 - PA28 - PA29 -) - -const ( - PB00 Pin = iota + 32 - PB01 - PB02 - PB03 - PB04 - PB05 - PB06 - PB07 - PB08 - PB09 - PB10 - PB11 - _ - _ - _ - _ - PB16 - PB17 - PB18 - PB19 - PB20 - PB21 - PB22 - PB23 -) - -const ( - PC00 Pin = iota + 64 - PC01 - PC02 - PC03 - PC04 - PC05 - PC06 - PC07 - PC08 - PC09 - PC10 - PC11 - PC12 - PC13 - PC14 - PC15 - PC16 - PC17 - PC18 - PC19 -) - -const ( - PD00 Pin = iota + 96 - PD01 - PD02 - PD03 - PD04 - PD05 - PD06 - PD07 - PD08 - PD09 - PD10 - PD11 - PD12 - PD13 - PD14 - PD15 -) - -const ( - PE00 Pin = iota + 128 - PE01 - PE02 - PE03 - PE04 - PE05 - PE06 - PE07 - PE08 - PE09 - PE10 - PE11 - PE12 - PE13 - PE14 - PE15 - PE16 - PE17 - PE18 - PE19 - PE20 - PE21 - PE22 - PE23 - PE24 - PE25 - PE26 - PE27 - PE28 -) - -//go:inline -func (p Pin) reg() (*nxp.GPIO_Type, *volatile.Register32, uint8) { - var gpio *nxp.GPIO_Type - var pcr *nxp.PORT_Type - - switch p / 32 { - case 0: - gpio, pcr = nxp.GPIOA, nxp.PORTA - case 1: - gpio, pcr = nxp.GPIOB, nxp.PORTB - case 2: - gpio, pcr = nxp.GPIOC, nxp.PORTC - case 3: - gpio, pcr = nxp.GPIOD, nxp.PORTD - case 5: - gpio, pcr = nxp.GPIOE, nxp.PORTE - default: - panic("invalid pin number") - } - - return gpio, &(*[32]volatile.Register32)(unsafe.Pointer(pcr))[p%32], uint8(p % 32) -} - -// Configure this pin with the given configuration. -func (p Pin) Configure(config PinConfig) { - gpio, pcr, pos := p.reg() - - switch config.Mode { - case PinOutput: - gpio.PDDR.SetBits(1 << pos) - pcr.Set((1 << nxp.PORT_PCR0_MUX_Pos) | nxp.PORT_PCR0_SRE | nxp.PORT_PCR0_DSE) - - case PinOutputOpenDrain: - gpio.PDDR.SetBits(1 << pos) - pcr.Set((1 << nxp.PORT_PCR0_MUX_Pos) | nxp.PORT_PCR0_SRE | nxp.PORT_PCR0_DSE | nxp.PORT_PCR0_ODE) - - case PinInput: - gpio.PDDR.ClearBits(1 << pos) - pcr.Set((1 << nxp.PORT_PCR0_MUX_Pos)) - - case PinInputPullup: - gpio.PDDR.ClearBits(1 << pos) - pcr.Set((1 << nxp.PORT_PCR0_MUX_Pos) | nxp.PORT_PCR0_PE | nxp.PORT_PCR0_PS) - - case PinInputPulldown: - gpio.PDDR.ClearBits(1 << pos) - pcr.Set((1 << nxp.PORT_PCR0_MUX_Pos) | nxp.PORT_PCR0_PE) - - case PinDisable: - gpio.PDDR.ClearBits(1 << pos) - pcr.Set((0 << nxp.PORT_PCR0_MUX_Pos)) - } -} - -// Set changes the value of the GPIO pin. The pin must be configured as output. -func (p Pin) Set(value bool) { - gpio, _, pos := p.reg() - if value { - gpio.PSOR.Set(1 << pos) - } else { - gpio.PCOR.Set(1 << pos) - } -} - -// Get returns the current value of a GPIO pin. -func (p Pin) Get() bool { - gpio, _, pos := p.reg() - return gpio.PDIR.HasBits(1 << pos) -} - -func (p Pin) Control() *volatile.Register32 { - _, pcr, _ := p.reg() - return pcr -} - -func (p Pin) Fast() FastPin { - gpio, _, pos := p.reg() - return FastPin{ - PDOR: gpio.PDOR.Bit(pos), - PSOR: gpio.PSOR.Bit(pos), - PCOR: gpio.PCOR.Bit(pos), - PTOR: gpio.PTOR.Bit(pos), - PDIR: gpio.PDIR.Bit(pos), - PDDR: gpio.PDDR.Bit(pos), - } -} - -type FastPin struct { - PDOR *volatile.BitRegister - PSOR *volatile.BitRegister - PCOR *volatile.BitRegister - PTOR *volatile.BitRegister - PDIR *volatile.BitRegister - PDDR *volatile.BitRegister -} - -func (p FastPin) Set() { p.PSOR.Set(true) } -func (p FastPin) Clear() { p.PCOR.Set(true) } -func (p FastPin) Toggle() { p.PTOR.Set(true) } -func (p FastPin) Write(v bool) { p.PDOR.Set(v) } -func (p FastPin) Read() bool { return p.PDIR.Get() } diff --git a/emb/machine/machine_nxpmk66f18_uart.go b/emb/machine/machine_nxpmk66f18_uart.go deleted file mode 100644 index a14d18f..0000000 --- a/emb/machine/machine_nxpmk66f18_uart.go +++ /dev/null @@ -1,309 +0,0 @@ -// Derivative work of Teensyduino Core Library -// http://www.pjrc.com/teensy/ -// Copyright (c) 2017 PJRC.COM, LLC. -// -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to -// permit persons to whom the Software is furnished to do so, subject to -// the following conditions: -// -// 1. The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// 2. If the Software is incorporated into a build system that allows -// selection among a list of target devices, then similar target -// devices manufactured by PJRC.COM must be included in the list of -// target devices and selectable in the same manner. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS -// BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. - -//go:build nxp && mk66f18 - -package machine - -import ( - "device/arm" - "device/nxp" - "errors" - "runtime/interrupt" - "runtime/volatile" - - _ "unsafe" // for go:linkname -) - -const ( - uartC2Enable = nxp.UART_C2_TE | nxp.UART_C2_RE | nxp.UART_C2_RIE | nxp.UART_C2_ILIE - uartC2TXActive = uartC2Enable | nxp.UART_C2_TIE - uartC2TXCompleting = uartC2Enable | nxp.UART_C2_TCIE - uartC2TXInactive = uartC2Enable - - uartIRQPriority = 64 - - // determined from UARTx_PFIFO - uartRXFIFODepth = 8 - uartTXFIFODepth = 8 -) - -var ( - ErrNotImplemented = errors.New("device has not been implemented") - ErrNotConfigured = errors.New("device has not been configured") -) - -// PutcharUART writes a byte to the UART synchronously, without using interrupts -// or calling the scheduler -func PutcharUART(u *UART, c byte) { - // ensure the UART has been configured - if !u.SCGC.HasBits(u.SCGCMask) { - u.configure(UARTConfig{}, false) - } - - for u.TCFIFO.Get() > 0 { - // busy wait - } - u.D.Set(c) - u.C2.Set(uartC2TXActive) -} - -// PollUART manually checks a UART status and calls the ISR. This should only be -// called by runtime.abort. -func PollUART(u *UART) { - if u.SCGC.HasBits(u.SCGCMask) { - u.handleStatusInterrupt(u.Interrupt) - } -} - -type UART struct { - *nxp.UART_Type - SCGC *volatile.Register32 - SCGCMask uint32 - - DefaultRX Pin - DefaultTX Pin - - // state - Buffer RingBuffer // RX Buffer - TXBuffer RingBuffer - Configured bool - Transmitting volatile.Register8 - Interrupt interrupt.Interrupt -} - -var ( - UART0 = &_UART0 - UART1 = &_UART1 - UART2 = &_UART2 - UART3 = &_UART3 - UART4 = &_UART4 - _UART0 = UART{UART_Type: nxp.UART0, SCGC: &nxp.SIM.SCGC4, SCGCMask: nxp.SIM_SCGC4_UART0, DefaultRX: defaultUART0RX, DefaultTX: defaultUART0TX} - _UART1 = UART{UART_Type: nxp.UART1, SCGC: &nxp.SIM.SCGC4, SCGCMask: nxp.SIM_SCGC4_UART1, DefaultRX: defaultUART1RX, DefaultTX: defaultUART1TX} - _UART2 = UART{UART_Type: nxp.UART2, SCGC: &nxp.SIM.SCGC4, SCGCMask: nxp.SIM_SCGC4_UART2, DefaultRX: defaultUART2RX, DefaultTX: defaultUART2TX} - _UART3 = UART{UART_Type: nxp.UART3, SCGC: &nxp.SIM.SCGC4, SCGCMask: nxp.SIM_SCGC4_UART3, DefaultRX: defaultUART3RX, DefaultTX: defaultUART3TX} - _UART4 = UART{UART_Type: nxp.UART4, SCGC: &nxp.SIM.SCGC1, SCGCMask: nxp.SIM_SCGC1_UART4, DefaultRX: defaultUART4RX, DefaultTX: defaultUART4TX} -) - -func init() { - UART0.Interrupt = interrupt.New(nxp.IRQ_UART0_RX_TX, _UART0.handleStatusInterrupt) - UART1.Interrupt = interrupt.New(nxp.IRQ_UART1_RX_TX, _UART1.handleStatusInterrupt) - UART2.Interrupt = interrupt.New(nxp.IRQ_UART2_RX_TX, _UART2.handleStatusInterrupt) - UART3.Interrupt = interrupt.New(nxp.IRQ_UART3_RX_TX, _UART3.handleStatusInterrupt) - UART4.Interrupt = interrupt.New(nxp.IRQ_UART4_RX_TX, _UART4.handleStatusInterrupt) -} - -// Configure the UART. -func (u *UART) Configure(config UARTConfig) { - u.configure(config, true) -} - -func (u *UART) configure(config UARTConfig, canSched bool) { - // from: serial_begin - - if !u.Configured { - u.Transmitting.Set(0) - - // turn on the clock - u.SCGC.Set(u.SCGCMask) - - // configure pins - u.DefaultRX.Control().Set(nxp.PORT_PCR0_PE | nxp.PORT_PCR0_PS | nxp.PORT_PCR0_PFE | (3 << nxp.PORT_PCR0_MUX_Pos)) - u.DefaultTX.Control().Set(nxp.PORT_PCR0_DSE | nxp.PORT_PCR0_SRE | (3 << nxp.PORT_PCR0_MUX_Pos)) - u.C1.Set(nxp.UART_C1_ILT) - } - - // default to 115200 baud - if config.BaudRate == 0 { - config.BaudRate = 115200 - } - - // copied from teensy core's BAUD2DIV macro - divisor := ((CPUFrequency() * 2) + (config.BaudRate >> 1)) / config.BaudRate - if divisor < 32 { - divisor = 32 - } - - if u.Configured { - // don't change baud rate mid transmit - if canSched { - u.Flush() - } else { - for u.Transmitting.Get() != 0 { - // busy wait flush - } - } - } - - // set the divisor - u.BDH.Set(uint8((divisor >> 13) & 0x1F)) - u.BDL.Set(uint8((divisor >> 5) & 0xFF)) - u.C4.Set(uint8(divisor & 0x1F)) - - if !u.Configured { - u.Configured = true - - u.C1.Set(nxp.UART_C1_ILT) - - // configure TX and RX watermark - u.TWFIFO.Set(2) // causes bit TDRE of S1 to set - u.RWFIFO.Set(4) // causes bit RDRF of S1 to set - - // enable FIFOs - u.PFIFO.Set(nxp.UART_PFIFO_TXFE | nxp.UART_PFIFO_RXFE) - - // setup interrupts - u.C2.Set(uartC2TXInactive) - u.Interrupt.SetPriority(uartIRQPriority) - u.Interrupt.Enable() - } -} - -func (u *UART) Disable() { - // from: serial_end - - // check if the device has been enabled already - if !u.SCGC.HasBits(u.SCGCMask) { - return - } - - u.Flush() - - u.Interrupt.Disable() - u.C2.Set(0) - - // reconfigure pin - u.DefaultRX.Configure(PinConfig{Mode: PinInputPullup}) - u.DefaultTX.Configure(PinConfig{Mode: PinInputPullup}) - - // clear flags - u.S1.Get() - u.D.Get() - u.Buffer.Clear() -} - -func (u *UART) Flush() { - for u.Transmitting.Get() != 0 { - gosched() - } -} - -func (u *UART) handleStatusInterrupt(interrupt.Interrupt) { - // from: uart0_status_isr - - // receive - if u.S1.HasBits(nxp.UART_S1_RDRF | nxp.UART_S1_IDLE) { - intrs := arm.DisableInterrupts() - avail := u.RCFIFO.Get() - if avail == 0 { - // The only way to clear the IDLE interrupt flag is - // to read the data register. But reading with no - // data causes a FIFO underrun, which causes the - // FIFO to return corrupted data. If anyone from - // Freescale reads this, what a poor design! There - // write should be a write-1-to-clear for IDLE. - u.D.Get() - // flushing the fifo recovers from the underrun, - // but there's a possible race condition where a - // new character could be received between reading - // RCFIFO == 0 and flushing the FIFO. To minimize - // the chance, interrupts are disabled so a higher - // priority interrupt (hopefully) doesn't delay. - // TODO: change this to disabling the IDLE interrupt - // which won't be simple, since we already manage - // which transmit interrupts are enabled. - u.CFIFO.Set(nxp.UART_CFIFO_RXFLUSH) - arm.EnableInterrupts(intrs) - - } else { - arm.EnableInterrupts(intrs) - - for { - u.Buffer.Put(u.D.Get()) - avail-- - if avail <= 0 { - break - } - } - } - } - - // transmit - if u.C2.HasBits(nxp.UART_C2_TIE) && u.S1.HasBits(nxp.UART_S1_TDRE) { - data := make([]byte, 0, uartTXFIFODepth) - avail := uartTXFIFODepth - u.TCFIFO.Get() - - // get avail bytes from ring buffer - for len(data) < int(avail) { - if b, ok := u.TXBuffer.Get(); ok { - data = append(data, b) - } else { - break - } - } - - // write data to FIFO - l := len(data) - for i, b := range data { - if i == l-1 { - // only clear TDRE on last write, per the manual - u.S1.Get() - } - u.D.Set(b) - } - - // if FIFO still has room, disable TIE, enable TCIE - if u.S1.HasBits(nxp.UART_S1_TDRE) { - u.C2.Set(uartC2TXCompleting) - } - } - - // transmit complete - if u.C2.HasBits(nxp.UART_C2_TCIE) && u.S1.HasBits(nxp.UART_S1_TC) { - u.Transmitting.Set(0) - u.C2.Set(uartC2TXInactive) - } -} - -// WriteByte writes a byte of data to the UART. -func (u *UART) writeByte(c byte) error { - if !u.Configured { - return ErrNotConfigured - } - - for !u.TXBuffer.Put(c) { - gosched() - } - - u.Transmitting.Set(1) - u.C2.Set(uartC2TXActive) - return nil -} - -func (uart *UART) flush() {} diff --git a/emb/machine/machine_rp2.go b/emb/machine/machine_rp2.go deleted file mode 100644 index 9afefa5..0000000 --- a/emb/machine/machine_rp2.go +++ /dev/null @@ -1,137 +0,0 @@ -//go:build rp2040 || rp2350 - -package machine - -import ( - "device/rp" - "runtime/interrupt" - "runtime/volatile" - "unsafe" -) - -const deviceName = rp.Device - -const ( - // Number of spin locks available - // Note: On RP2350, most spinlocks are unusable due to Errata 2 - _NUMSPINLOCKS = 32 - _PICO_SPINLOCK_ID_IRQ = 9 - // is48Pin notes whether the chip is RP2040 with 32 pins or RP2350 with 48 pins. - is48Pin = _NUMBANK0_GPIOS == 48 -) - -// UART on the RP2040 -var ( - UART0 = &_UART0 - _UART0 = UART{ - Buffer: NewRingBuffer(), - Bus: rp.UART0, - } - - UART1 = &_UART1 - _UART1 = UART{ - Buffer: NewRingBuffer(), - Bus: rp.UART1, - } -) - -func init() { - UART0.Interrupt = interrupt.New(rp.IRQ_UART0_IRQ, _UART0.handleInterrupt) - UART1.Interrupt = interrupt.New(rp.IRQ_UART1_IRQ, _UART1.handleInterrupt) -} - -//go:linkname machineInit runtime.machineInit -func machineInit() { - // Reset all peripherals to put system into a known state, - // except for QSPI pads and the XIP IO bank, as this is fatal if running from flash - // and the PLLs, as this is fatal if clock muxing has not been reset on this boot - // and USB, syscfg, as this disturbs USB-to-SWD on core 1 - bits := ^uint32(initDontReset) - resetBlock(bits) - - // Remove reset from peripherals which are clocked only by clkSys and - // clkRef. Other peripherals stay in reset until we've configured clocks. - bits = ^uint32(initUnreset) - unresetBlockWait(bits) - - clocks.init() - - // Peripheral clocks should now all be running - unresetBlockWait(RESETS_RESET_Msk) -} - -//go:linkname ticks runtime.machineTicks -func ticks() uint64 { - return timer.timeElapsed() -} - -//go:linkname lightSleep runtime.machineLightSleep -func lightSleep(ticks uint64) { - timer.lightSleep(ticks) -} - -// CurrentCore returns the core number the call was made from. -func CurrentCore() int { - return int(rp.SIO.CPUID.Get()) -} - -// NumCores returns number of cores available on the device. -func NumCores() int { return 2 } - -// ChipVersion returns the version of the chip. 1 is returned for B0 and B1 -// chip. -func ChipVersion() uint8 { - const ( - SYSINFO_BASE = 0x40000000 - SYSINFO_CHIP_ID_OFFSET = 0x00000000 - SYSINFO_CHIP_ID_REVISION_BITS = 0xf0000000 - SYSINFO_CHIP_ID_REVISION_LSB = 28 - ) - - // First register of sysinfo is chip id - chipID := *(*uint32)(unsafe.Pointer(uintptr(SYSINFO_BASE + SYSINFO_CHIP_ID_OFFSET))) - // Version 1 == B0/B1 - version := (chipID & SYSINFO_CHIP_ID_REVISION_BITS) >> SYSINFO_CHIP_ID_REVISION_LSB - return uint8(version) -} - -// Single DMA channel. See rp.DMA_Type. -type dmaChannel struct { - READ_ADDR volatile.Register32 - WRITE_ADDR volatile.Register32 - TRANS_COUNT volatile.Register32 - CTRL_TRIG volatile.Register32 - _ [12]volatile.Register32 // aliases -} - -// Static assignment of DMA channels to peripherals. -// Allocating them statically is good enough for now. If lots of peripherals use -// DMA, these might need to be assigned at runtime. -const ( - spi0DMAChannel = iota - spi1DMAChannel -) - -// DMA channels usable on the RP2040. -var dmaChannels = (*[12 + 4*rp2350ExtraReg]dmaChannel)(unsafe.Pointer(rp.DMA)) - -//go:inline -func boolToBit(a bool) uint32 { - if a { - return 1 - } - return 0 -} - -//go:inline -func u32max(a, b uint32) uint32 { - if a > b { - return a - } - return b -} - -//go:inline -func isReservedI2CAddr(addr uint8) bool { - return (addr&0x78) == 0 || (addr&0x78) == 0x78 -} diff --git a/emb/machine/machine_rp2040_rom.go b/emb/machine/machine_rp2040_rom.go deleted file mode 100644 index 5541e2a..0000000 --- a/emb/machine/machine_rp2040_rom.go +++ /dev/null @@ -1,254 +0,0 @@ -//go:build tinygo && rp2040 - -package machine - -import ( - "runtime/interrupt" - "unsafe" -) - -/* -// https://github.com/raspberrypi/pico-sdk -// src/rp2_common/pico_bootrom/include/pico/bootrom.h - -#define ROM_FUNC_POPCOUNT32 ROM_TABLE_CODE('P', '3') -#define ROM_FUNC_REVERSE32 ROM_TABLE_CODE('R', '3') -#define ROM_FUNC_CLZ32 ROM_TABLE_CODE('L', '3') -#define ROM_FUNC_CTZ32 ROM_TABLE_CODE('T', '3') -#define ROM_FUNC_MEMSET ROM_TABLE_CODE('M', 'S') -#define ROM_FUNC_MEMSET4 ROM_TABLE_CODE('S', '4') -#define ROM_FUNC_MEMCPY ROM_TABLE_CODE('M', 'C') -#define ROM_FUNC_MEMCPY44 ROM_TABLE_CODE('C', '4') -#define ROM_FUNC_RESET_USB_BOOT ROM_TABLE_CODE('U', 'B') -#define ROM_FUNC_CONNECT_INTERNAL_FLASH ROM_TABLE_CODE('I', 'F') -#define ROM_FUNC_FLASH_EXIT_XIP ROM_TABLE_CODE('E', 'X') -#define ROM_FUNC_FLASH_RANGE_ERASE ROM_TABLE_CODE('R', 'E') -#define ROM_FUNC_FLASH_RANGE_PROGRAM ROM_TABLE_CODE('R', 'P') -#define ROM_FUNC_FLASH_FLUSH_CACHE ROM_TABLE_CODE('F', 'C') -#define ROM_FUNC_FLASH_ENTER_CMD_XIP ROM_TABLE_CODE('C', 'X') - -#define ROM_TABLE_CODE(c1, c2) ((c1) | ((c2) << 8)) - -typedef unsigned char uint8_t; -typedef unsigned short uint16_t; -typedef unsigned long uint32_t; -typedef unsigned long size_t; -typedef unsigned long uintptr_t; - -#define false 0 -#define true 1 -typedef int bool; - -#define ram_func __attribute__((section(".ramfuncs"),noinline)) - -typedef void *(*rom_table_lookup_fn)(uint16_t *table, uint32_t code); -typedef void __attribute__((noreturn)) (*rom_reset_usb_boot_fn)(uint32_t, uint32_t); -typedef void (*flash_init_boot2_copyout_fn)(void); -typedef void (*flash_enable_xip_via_boot2_fn)(void); -typedef void (*flash_exit_xip_fn)(void); -typedef void (*flash_flush_cache_fn)(void); -typedef void (*flash_connect_internal_fn)(void); -typedef void (*flash_range_erase_fn)(uint32_t, size_t, uint32_t, uint16_t); -typedef void (*flash_range_program_fn)(uint32_t, const uint8_t*, size_t); - -static inline __attribute__((always_inline)) void __compiler_memory_barrier(void) { - __asm__ volatile ("" : : : "memory"); -} - -#define rom_hword_as_ptr(rom_address) (void *)(uintptr_t)(*(uint16_t *)(uintptr_t)(rom_address)) - -void *rom_func_lookup(uint32_t code) { - rom_table_lookup_fn rom_table_lookup = (rom_table_lookup_fn) rom_hword_as_ptr(0x18); - uint16_t *func_table = (uint16_t *) rom_hword_as_ptr(0x14); - return rom_table_lookup(func_table, code); -} - -void reset_usb_boot(uint32_t usb_activity_gpio_pin_mask, uint32_t disable_interface_mask) { - rom_reset_usb_boot_fn func = (rom_reset_usb_boot_fn) rom_func_lookup(ROM_FUNC_RESET_USB_BOOT); - func(usb_activity_gpio_pin_mask, disable_interface_mask); -} - -#define FLASH_BLOCK_ERASE_CMD 0xd8 - -#define FLASH_PAGE_SIZE (1u << 8) -#define FLASH_SECTOR_SIZE (1u << 12) -#define FLASH_BLOCK_SIZE (1u << 16) - -#define BOOT2_SIZE_WORDS 64 -#define XIP_BASE 0x10000000 - -static uint32_t boot2_copyout[BOOT2_SIZE_WORDS]; -static bool boot2_copyout_valid = false; - -static ram_func void flash_init_boot2_copyout() { - if (boot2_copyout_valid) - return; - for (int i = 0; i < BOOT2_SIZE_WORDS; ++i) - boot2_copyout[i] = ((uint32_t *)XIP_BASE)[i]; - __compiler_memory_barrier(); - boot2_copyout_valid = true; -} - -static ram_func void flash_enable_xip_via_boot2() { - ((void (*)(void))boot2_copyout+1)(); -} - -#define IO_QSPI_BASE 0x40018000 -#define IO_QSPI_GPIO_QSPI_SS_CTRL_OUTOVER_BITS 0x00000300 -#define IO_QSPI_GPIO_QSPI_SS_CTRL_OUTOVER_MSB 9 -#define IO_QSPI_GPIO_QSPI_SS_CTRL_OUTOVER_LSB 8 -#define IO_QSPI_GPIO_QSPI_SS_CTRL_OUTOVER_VALUE_LOW 0x2 -#define IO_QSPI_GPIO_QSPI_SS_CTRL_OUTOVER_VALUE_HIGH 0x3 - -#define XIP_SSI_BASE 0x18000000 -#define ssi_hw ((ssi_hw_t *)XIP_SSI_BASE) -#define SSI_SR_OFFSET 0x00000028 -#define SSI_DR0_OFFSET 0x00000060 -#define SSI_SR_TFNF_BITS 0x00000002 -#define SSI_SR_RFNE_BITS 0x00000008 - -void ram_func flash_cs_force(bool high) { - uint32_t field_val = high ? - IO_QSPI_GPIO_QSPI_SS_CTRL_OUTOVER_VALUE_HIGH : - IO_QSPI_GPIO_QSPI_SS_CTRL_OUTOVER_VALUE_LOW; - - // &ioqspi_hw->io[1].ctrl - uint32_t *addr = (uint32_t*)(IO_QSPI_BASE + (1 * 8) + 4); - - *addr = ((*addr) & !IO_QSPI_GPIO_QSPI_SS_CTRL_OUTOVER_BITS) - | (field_val << IO_QSPI_GPIO_QSPI_SS_CTRL_OUTOVER_LSB); - -} - -// See https://github.com/raspberrypi/pico-sdk/blob/master/src/rp2_common/hardware_flash/flash.c#L86 -void ram_func flash_range_write(uint32_t offset, const uint8_t *data, size_t count) -{ - flash_range_program_fn flash_range_program_func = (flash_range_program_fn) rom_func_lookup(ROM_FUNC_FLASH_RANGE_PROGRAM); - flash_connect_internal_fn flash_connect_internal_func = (flash_connect_internal_fn) rom_func_lookup(ROM_FUNC_CONNECT_INTERNAL_FLASH); - flash_exit_xip_fn flash_exit_xip_func = (flash_exit_xip_fn) rom_func_lookup(ROM_FUNC_FLASH_EXIT_XIP); - flash_flush_cache_fn flash_flush_cache_func = (flash_flush_cache_fn) rom_func_lookup(ROM_FUNC_FLASH_FLUSH_CACHE); - - flash_init_boot2_copyout(); - - __compiler_memory_barrier(); - - flash_connect_internal_func(); - flash_exit_xip_func(); - - flash_range_program_func(offset, data, count); - flash_flush_cache_func(); - flash_enable_xip_via_boot2(); -} - -void ram_func flash_erase_blocks(uint32_t offset, size_t count) -{ - flash_range_erase_fn flash_range_erase_func = (flash_range_erase_fn) rom_func_lookup(ROM_FUNC_FLASH_RANGE_ERASE); - flash_connect_internal_fn flash_connect_internal_func = (flash_connect_internal_fn) rom_func_lookup(ROM_FUNC_CONNECT_INTERNAL_FLASH); - flash_exit_xip_fn flash_exit_xip_func = (flash_exit_xip_fn) rom_func_lookup(ROM_FUNC_FLASH_EXIT_XIP); - flash_flush_cache_fn flash_flush_cache_func = (flash_flush_cache_fn) rom_func_lookup(ROM_FUNC_FLASH_FLUSH_CACHE); - - flash_init_boot2_copyout(); - - __compiler_memory_barrier(); - - flash_connect_internal_func(); - flash_exit_xip_func(); - - flash_range_erase_func(offset, count, FLASH_BLOCK_SIZE, FLASH_BLOCK_ERASE_CMD); - flash_flush_cache_func(); - flash_enable_xip_via_boot2(); -} - -void ram_func flash_do_cmd(const uint8_t *txbuf, uint8_t *rxbuf, size_t count) { - flash_connect_internal_fn flash_connect_internal_func = (flash_connect_internal_fn) rom_func_lookup(ROM_FUNC_CONNECT_INTERNAL_FLASH); - flash_exit_xip_fn flash_exit_xip_func = (flash_exit_xip_fn) rom_func_lookup(ROM_FUNC_FLASH_EXIT_XIP); - flash_flush_cache_fn flash_flush_cache_func = (flash_flush_cache_fn) rom_func_lookup(ROM_FUNC_FLASH_FLUSH_CACHE); - - flash_init_boot2_copyout(); - - __compiler_memory_barrier(); - - flash_connect_internal_func(); - flash_exit_xip_func(); - - flash_cs_force(0); - size_t tx_remaining = count; - size_t rx_remaining = count; - // We may be interrupted -- don't want FIFO to overflow if we're distracted. - const size_t max_in_flight = 16 - 2; - while (tx_remaining || rx_remaining) { - uint32_t flags = *(uint32_t*)(XIP_SSI_BASE + SSI_SR_OFFSET); - bool can_put = !!(flags & SSI_SR_TFNF_BITS); - bool can_get = !!(flags & SSI_SR_RFNE_BITS); - if (can_put && tx_remaining && rx_remaining - tx_remaining < max_in_flight) { - *(uint32_t*)(XIP_SSI_BASE + SSI_DR0_OFFSET) = *txbuf++; - --tx_remaining; - } - if (can_get && rx_remaining) { - *rxbuf++ = (uint8_t)*(uint32_t*)(XIP_SSI_BASE + SSI_DR0_OFFSET); - --rx_remaining; - } - } - flash_cs_force(1); - - flash_flush_cache_func(); - flash_enable_xip_via_boot2(); -} - -*/ -import "C" - -func enterBootloader() { - C.reset_usb_boot(0, 0) -} - -func doFlashCommand(tx []byte, rx []byte) error { - if len(tx) != len(rx) { - return errFlashInvalidWriteLength - } - - C.flash_do_cmd( - (*C.uint8_t)(unsafe.Pointer(&tx[0])), - (*C.uint8_t)(unsafe.Pointer(&rx[0])), - C.ulong(len(tx))) - - return nil -} - -// Flash related code -const memoryStart = C.XIP_BASE // memory start for purpose of erase - -func (f flashBlockDevice) writeAt(p []byte, off int64) (n int, err error) { - if writeAddress(off)+uintptr(C.XIP_BASE) > FlashDataEnd() { - return 0, errFlashCannotWritePastEOF - } - - state := interrupt.Disable() - defer interrupt.Restore(state) - - // rp2040 writes to offset, not actual address - // e.g. real address 0x10003000 is written to at - // 0x00003000 - address := writeAddress(off) - padded := flashPad(p, int(f.WriteBlockSize())) - - C.flash_range_write(C.uint32_t(address), - (*C.uint8_t)(unsafe.Pointer(&padded[0])), - C.ulong(len(padded))) - - return len(padded), nil -} - -func (f flashBlockDevice) eraseBlocks(start, length int64) error { - address := writeAddress(start * f.EraseBlockSize()) - if address+uintptr(C.XIP_BASE) > FlashDataEnd() { - return errFlashCannotErasePastEOF - } - - state := interrupt.Disable() - defer interrupt.Restore(state) - - C.flash_erase_blocks(C.uint32_t(address), C.ulong(length*f.EraseBlockSize())) - - return nil -} diff --git a/emb/machine/machine_rp2040_rtc.go b/emb/machine/machine_rp2040_rtc.go deleted file mode 100644 index 192e187..0000000 --- a/emb/machine/machine_rp2040_rtc.go +++ /dev/null @@ -1,240 +0,0 @@ -//go:build rp2040 - -// Implementation based on code located here: -// https://github.com/raspberrypi/pico-sdk/blob/master/src/rp2_common/hardware_rtc/rtc.c - -package machine - -import ( - "device/rp" - "errors" - "runtime/interrupt" - "unsafe" -) - -type rtcType rp.RTC_Type - -type rtcTime struct { - Year int16 - Month int8 - Day int8 - Dotw int8 - Hour int8 - Min int8 - Sec int8 -} - -var RTC = (*rtcType)(unsafe.Pointer(rp.RTC)) - -const ( - second = 1 - minute = 60 * second - hour = 60 * minute - day = 24 * hour -) - -var ( - rtcAlarmRepeats bool - rtcCallback func() - rtcEpoch = rtcTime{ - Year: 1970, Month: 1, Day: 1, Dotw: 4, Hour: 0, Min: 0, Sec: 0, - } -) - -var ( - ErrRtcDelayTooSmall = errors.New("RTC interrupt deplay is too small, shall be at least 1 second") - ErrRtcDelayTooLarge = errors.New("RTC interrupt deplay is too large, shall be no more than 1 day") -) - -// SetInterrupt configures delayed and optionally recurring interrupt by real time clock. -// -// Delay is specified in whole seconds, allowed range depends on platform. -// Zero delay disables previously configured interrupt, if any. -// -// RP2040 implementation allows delay to be up to 1 day, otherwise a respective error is emitted. -func (rtc *rtcType) SetInterrupt(delay uint32, repeat bool, callback func()) error { - - // Verify delay range - if delay > day { - return ErrRtcDelayTooLarge - } - - // De-configure delayed interrupt if delay is zero - if delay == 0 { - rtc.disableInterruptMatch() - return nil - } - - // Configure delayed interrupt - rtc.setDivider() - - rtcAlarmRepeats = repeat - rtcCallback = callback - - err := rtc.setTime(rtcEpoch) - if err != nil { - return err - } - rtc.setAlarm(toAlarmTime(delay), callback) - - return nil -} - -func toAlarmTime(delay uint32) rtcTime { - result := rtcEpoch - remainder := delay + 1 // needed "+1", otherwise alarm fires one second too early - if remainder >= hour { - result.Hour = int8(remainder / hour) - remainder %= hour - } - if remainder >= minute { - result.Min = int8(remainder / minute) - remainder %= minute - } - result.Sec = int8(remainder) - return result -} - -func (rtc *rtcType) setDivider() { - // Get clk_rtc freq and make sure it is running - rtcFreq := configuredFreq[clkRTC] - if rtcFreq == 0 { - panic("can not set RTC divider, clock is not running") - } - - // Take rtc out of reset now that we know clk_rtc is running - resetBlock(rp.RESETS_RESET_RTC) - unresetBlockWait(rp.RESETS_RESET_RTC) - - // Set up the 1 second divider. - // If rtc_freq is 400 then clkdiv_m1 should be 399 - rtcFreq -= 1 - - // Check the freq is not too big to divide - if rtcFreq > rp.RTC_CLKDIV_M1_CLKDIV_M1_Msk { - panic("can not set RTC divider, clock frequency is too big to divide") - } - - // Write divide value - rtc.CLKDIV_M1.Set(rtcFreq) -} - -// setTime configures RTC with supplied time, initialises and activates it. -func (rtc *rtcType) setTime(t rtcTime) error { - - // Disable RTC and wait while it is still running - rtc.CTRL.Set(0) - for rtc.isActive() { - } - - rtc.SETUP_0.Set((uint32(t.Year) << rp.RTC_SETUP_0_YEAR_Pos) | - (uint32(t.Month) << rp.RTC_SETUP_0_MONTH_Pos) | - (uint32(t.Day) << rp.RTC_SETUP_0_DAY_Pos)) - - rtc.SETUP_1.Set((uint32(t.Dotw) << rp.RTC_SETUP_1_DOTW_Pos) | - (uint32(t.Hour) << rp.RTC_SETUP_1_HOUR_Pos) | - (uint32(t.Min) << rp.RTC_SETUP_1_MIN_Pos) | - (uint32(t.Sec) << rp.RTC_SETUP_1_SEC_Pos)) - - // Load setup values into RTC clock domain - rtc.CTRL.SetBits(rp.RTC_CTRL_LOAD) - - // Enable RTC and wait for it to be running - rtc.CTRL.SetBits(rp.RTC_CTRL_RTC_ENABLE) - for !rtc.isActive() { - } - - return nil -} - -func (rtc *rtcType) isActive() bool { - return rtc.CTRL.HasBits(rp.RTC_CTRL_RTC_ACTIVE) -} - -// setAlarm configures alarm in RTC and arms it. -// The callback is executed in the context of an interrupt handler, -// so regular restructions for this sort of code apply: no blocking, no memory allocation, etc. -func (rtc *rtcType) setAlarm(t rtcTime, callback func()) { - - rtc.disableInterruptMatch() - - // Clear all match enable bits - rtc.IRQ_SETUP_0.ClearBits(rp.RTC_IRQ_SETUP_0_YEAR_ENA | rp.RTC_IRQ_SETUP_0_MONTH_ENA | rp.RTC_IRQ_SETUP_0_DAY_ENA) - rtc.IRQ_SETUP_1.ClearBits(rp.RTC_IRQ_SETUP_1_DOTW_ENA | rp.RTC_IRQ_SETUP_1_HOUR_ENA | rp.RTC_IRQ_SETUP_1_MIN_ENA | rp.RTC_IRQ_SETUP_1_SEC_ENA) - - // Only add to setup if it isn't -1 and set the match enable bits for things we care about - if t.Year >= 0 { - rtc.IRQ_SETUP_0.SetBits(uint32(t.Year) << rp.RTC_SETUP_0_YEAR_Pos) - rtc.IRQ_SETUP_0.SetBits(rp.RTC_IRQ_SETUP_0_YEAR_ENA) - } - - if t.Month >= 0 { - rtc.IRQ_SETUP_0.SetBits(uint32(t.Month) << rp.RTC_SETUP_0_MONTH_Pos) - rtc.IRQ_SETUP_0.SetBits(rp.RTC_IRQ_SETUP_0_MONTH_ENA) - } - - if t.Day >= 0 { - rtc.IRQ_SETUP_0.SetBits(uint32(t.Day) << rp.RTC_SETUP_0_DAY_Pos) - rtc.IRQ_SETUP_0.SetBits(rp.RTC_IRQ_SETUP_0_DAY_ENA) - } - - if t.Dotw >= 0 { - rtc.IRQ_SETUP_1.SetBits(uint32(t.Dotw) << rp.RTC_SETUP_1_DOTW_Pos) - rtc.IRQ_SETUP_1.SetBits(rp.RTC_IRQ_SETUP_1_DOTW_ENA) - } - - if t.Hour >= 0 { - rtc.IRQ_SETUP_1.SetBits(uint32(t.Hour) << rp.RTC_SETUP_1_HOUR_Pos) - rtc.IRQ_SETUP_1.SetBits(rp.RTC_IRQ_SETUP_1_HOUR_ENA) - } - - if t.Min >= 0 { - rtc.IRQ_SETUP_1.SetBits(uint32(t.Min) << rp.RTC_SETUP_1_MIN_Pos) - rtc.IRQ_SETUP_1.SetBits(rp.RTC_IRQ_SETUP_1_MIN_ENA) - } - - if t.Sec >= 0 { - rtc.IRQ_SETUP_1.SetBits(uint32(t.Sec) << rp.RTC_SETUP_1_SEC_Pos) - rtc.IRQ_SETUP_1.SetBits(rp.RTC_IRQ_SETUP_1_SEC_ENA) - } - - // Enable the IRQ at the proc - interrupt.New(rp.IRQ_RTC_IRQ, rtcHandleInterrupt).Enable() - - // Enable the IRQ at the peri - rtc.INTE.Set(rp.RTC_INTE_RTC) - - rtc.enableInterruptMatch() -} - -func (rtc *rtcType) enableInterruptMatch() { - // Set matching and wait for it to be enabled - rtc.IRQ_SETUP_0.SetBits(rp.RTC_IRQ_SETUP_0_MATCH_ENA) - for !rtc.IRQ_SETUP_0.HasBits(rp.RTC_IRQ_SETUP_0_MATCH_ACTIVE) { - } -} - -func (rtc *rtcType) disableInterruptMatch() { - // Disable matching and wait for it to stop being active - rtc.IRQ_SETUP_0.ClearBits(rp.RTC_IRQ_SETUP_0_MATCH_ENA) - for rtc.IRQ_SETUP_0.HasBits(rp.RTC_IRQ_SETUP_0_MATCH_ACTIVE) { - } -} - -func rtcHandleInterrupt(itr interrupt.Interrupt) { - // Always disable the alarm to clear the current IRQ. - // Even if it is a repeatable alarm, we don't want it to keep firing. - // If it matches on a second it can keep firing for that second. - RTC.disableInterruptMatch() - - // Call user callback function - if rtcCallback != nil { - rtcCallback() - } - - if rtcAlarmRepeats { - // If it is a repeatable alarm, reset time and re-enable the alarm. - RTC.setTime(rtcEpoch) - RTC.enableInterruptMatch() - } -} diff --git a/emb/machine/machine_rp2040_simulator.go b/emb/machine/machine_rp2040_simulator.go deleted file mode 100644 index 6c1d106..0000000 --- a/emb/machine/machine_rp2040_simulator.go +++ /dev/null @@ -1,96 +0,0 @@ -//go:build !baremetal && (ae_rp2040 || badger2040_w || badger2040 || challenger_rp2040 || elecrow_rp2040 || feather_rp2040 || gopher_badge || kb2040 || macropad_rp2040 || nano_rp2040 || pico || qtpy_rp2040 || thingplus_rp2040 || thumby || trinkey_qt2040 || tufty2040 || waveshare_rp2040_tiny || waveshare_rp2040_zero || xiao_rp2040) - -// Simulator support for the RP2040. -// -// This is *only* for the RP2040. RP2350 is a different chip with slightly -// different characteristics. - -package machine - -var PWM0 = &timerType{ - instance: 0, - frequency: 200e6, - bits: 16, - prescalers: []int{1, 2, 4, 8, 16, 32, 64, 128, 256}, // actually a continuing range, TODO - channelPins: [][]Pin{ - {GPIO0, GPIO16}, // channel A (0) - {GPIO1, GPIO17}, // channel B (1) - }, -} - -var PWM1 = &timerType{ - instance: 0, - frequency: 200e6, - bits: 16, - prescalers: []int{1, 2, 4, 8, 16, 32, 64, 128, 256}, - channelPins: [][]Pin{ - {GPIO2, GPIO18}, // channel A (0) - {GPIO3, GPIO19}, // channel B (1) - }, -} - -var PWM2 = &timerType{ - instance: 0, - frequency: 200e6, - bits: 16, - prescalers: []int{1, 2, 4, 8, 16, 32, 64, 128, 256}, - channelPins: [][]Pin{ - {GPIO4, GPIO20}, // channel A (0) - {GPIO5, GPIO21}, // channel B (1) - }, -} - -var PWM3 = &timerType{ - instance: 0, - frequency: 200e6, - bits: 16, - prescalers: []int{1, 2, 4, 8, 16, 32, 64, 128, 256}, - channelPins: [][]Pin{ - {GPIO6, GPIO22}, // channel A (0) - {GPIO7, GPIO23}, // channel B (1) - }, -} - -var PWM4 = &timerType{ - instance: 0, - frequency: 200e6, - bits: 16, - prescalers: []int{1, 2, 4, 8, 16, 32, 64, 128, 256}, - channelPins: [][]Pin{ - {GPIO8, GPIO24}, // channel A (0) - {GPIO9, GPIO25}, // channel B (1) - }, -} - -var PWM5 = &timerType{ - instance: 0, - frequency: 200e6, - bits: 16, - prescalers: []int{1, 2, 4, 8, 16, 32, 64, 128, 256}, - channelPins: [][]Pin{ - {GPIO10, GPIO26}, // channel A (0) - {GPIO11, GPIO27}, // channel B (1) - }, -} - -var PWM6 = &timerType{ - instance: 0, - frequency: 200e6, - bits: 16, - prescalers: []int{1, 2, 4, 8, 16, 32, 64, 128, 256}, - channelPins: [][]Pin{ - {GPIO12, GPIO28}, // channel A (0) - {GPIO13, GPIO29}, // channel B (1) - }, -} - -var PWM7 = &timerType{ - instance: 0, - frequency: 200e6, - bits: 16, - prescalers: []int{1, 2, 4, 8, 16, 32, 64, 128, 256}, - channelPins: [][]Pin{ - {GPIO14}, // channel A (0) - {GPIO15}, // channel B (1) - }, -} diff --git a/emb/machine/machine_rp2040_usb.go b/emb/machine/machine_rp2040_usb.go deleted file mode 100644 index 087e3bf..0000000 --- a/emb/machine/machine_rp2040_usb.go +++ /dev/null @@ -1,148 +0,0 @@ -//go:build rp2040 - -package machine - -import ( - "device/rp" - "machine/usb" - "runtime/interrupt" -) - -// Configure the USB peripheral. The config is here for compatibility with the UART interface. -func (dev *USBDevice) Configure(config UARTConfig) { - // Reset usb controller - resetBlock(rp.RESETS_RESET_USBCTRL) - unresetBlockWait(rp.RESETS_RESET_USBCTRL) - - // Clear any previous state in dpram just in case - _usbDPSRAM.clear() - - // Enable USB interrupt at processor - rp.USBCTRL_REGS.INTE.Set(0) - intr := interrupt.New(rp.IRQ_USBCTRL_IRQ, handleUSBIRQ) - intr.SetPriority(0x00) - intr.Enable() - irqSet(rp.IRQ_USBCTRL_IRQ, true) - - // Mux the controller to the onboard usb phy - rp.USBCTRL_REGS.USB_MUXING.Set(rp.USBCTRL_REGS_USB_MUXING_TO_PHY | rp.USBCTRL_REGS_USB_MUXING_SOFTCON) - - // Force VBUS detect so the device thinks it is plugged into a host - rp.USBCTRL_REGS.USB_PWR.Set(rp.USBCTRL_REGS_USB_PWR_VBUS_DETECT | rp.USBCTRL_REGS_USB_PWR_VBUS_DETECT_OVERRIDE_EN) - - // Enable the USB controller in device mode. - rp.USBCTRL_REGS.MAIN_CTRL.Set(rp.USBCTRL_REGS_MAIN_CTRL_CONTROLLER_EN) - - // Enable an interrupt per EP0 transaction - rp.USBCTRL_REGS.SIE_CTRL.Set(rp.USBCTRL_REGS_SIE_CTRL_EP0_INT_1BUF) - - // Enable interrupts for when a buffer is done, when the bus is reset, - // and when a setup packet is received - rp.USBCTRL_REGS.INTE.Set(rp.USBCTRL_REGS_INTE_BUFF_STATUS | - rp.USBCTRL_REGS_INTE_BUS_RESET | - rp.USBCTRL_REGS_INTE_SETUP_REQ) - - // Present full speed device by enabling pull up on DP - rp.USBCTRL_REGS.SIE_CTRL.SetBits(rp.USBCTRL_REGS_SIE_CTRL_PULLUP_EN) -} - -func handleUSBIRQ(intr interrupt.Interrupt) { - status := rp.USBCTRL_REGS.INTS.Get() - - // Setup packet received - if (status & rp.USBCTRL_REGS_INTS_SETUP_REQ) > 0 { - rp.USBCTRL_REGS.SIE_STATUS.Set(rp.USBCTRL_REGS_SIE_STATUS_SETUP_REC) - setup := usb.NewSetup(_usbDPSRAM.setupBytes()) - - ok := false - if (setup.BmRequestType & usb.REQUEST_TYPE) == usb.REQUEST_STANDARD { - // Standard Requests - ok = handleStandardSetup(setup) - } else { - // Class Interface Requests - if setup.WIndex < uint16(len(usbSetupHandler)) && usbSetupHandler[setup.WIndex] != nil { - ok = usbSetupHandler[setup.WIndex](setup) - } - } - - if !ok { - // Stall endpoint? - USBDev.SetStallEPIn(0) - } - - } - - // Buffer status, one or more buffers have completed - if (status & rp.USBCTRL_REGS_INTS_BUFF_STATUS) > 0 { - if sendOnEP0DATADONE.offset > 0 { - ep := uint32(0) - data := sendOnEP0DATADONE.data - count := len(data) - sendOnEP0DATADONE.offset - if ep == 0 && count > usb.EndpointPacketSize { - count = usb.EndpointPacketSize - } - - sendViaEPIn(ep, data[sendOnEP0DATADONE.offset:], count) - sendOnEP0DATADONE.offset += count - if sendOnEP0DATADONE.offset == len(data) { - sendOnEP0DATADONE.offset = 0 - } - } - - s2 := rp.USBCTRL_REGS.BUFF_STATUS.Get() - - // OUT (PC -> rp2040) - for i := 0; i < 16; i++ { - if s2&(1<<(i*2+1)) > 0 { - buf := handleEndpointRx(uint32(i)) - if usbRxHandler[i] == nil || usbRxHandler[i](buf) { - AckUsbOutTransfer(uint32(i)) - } - } - } - - // IN (rp2040 -> PC) - for i := 0; i < 16; i++ { - if s2&(1<<(i*2)) > 0 { - if usbTxHandler[i] != nil { - usbTxHandler[i]() - } - } - } - - rp.USBCTRL_REGS.BUFF_STATUS.Set(s2) - } - - // Bus is reset - if (status & rp.USBCTRL_REGS_INTS_BUS_RESET) > 0 { - rp.USBCTRL_REGS.SIE_STATUS.Set(rp.USBCTRL_REGS_SIE_STATUS_BUS_RESET) - fixRP2040UsbDeviceEnumeration() - - rp.USBCTRL_REGS.ADDR_ENDP.Set(0) - initEndpoint(0, usb.ENDPOINT_TYPE_CONTROL) - } -} - -func handleUSBSetAddress(setup usb.Setup) bool { - // Using 570μs timeout which is exactly the same as SAMD21. - const ackTimeout = 570 - - rp.USBCTRL_REGS.SIE_STATUS.Set(rp.USBCTRL_REGS_SIE_STATUS_ACK_REC) - sendUSBPacket(0, []byte{}, 0) - - // Wait for transfer to complete with a timeout. - t := timer.timeElapsed() - for (rp.USBCTRL_REGS.SIE_STATUS.Get() & rp.USBCTRL_REGS_SIE_STATUS_ACK_REC) == 0 { - if dt := timer.timeElapsed() - t; dt >= ackTimeout { - return false - } - } - - // Set the device address to that requested by host. - rp.USBCTRL_REGS.ADDR_ENDP.Set(uint32(setup.WValueL) & rp.USBCTRL_REGS_ADDR_ENDP_ADDRESS_Msk) - return true -} - -func armEPZeroStall() { - rp.USBCTRL_REGS.EP_STALL_ARM.Set(rp.USBCTRL_REGS_EP_STALL_ARM_EP0_IN) -} diff --git a/emb/machine/machine_rp2040_usb_fix_usb_device_enumeration.go b/emb/machine/machine_rp2040_usb_fix_usb_device_enumeration.go deleted file mode 100644 index f027f94..0000000 --- a/emb/machine/machine_rp2040_usb_fix_usb_device_enumeration.go +++ /dev/null @@ -1,120 +0,0 @@ -//go:build rp2040 - -package machine - -import ( - "device/arm" - "device/rp" -) - -// https://github.com/raspberrypi/pico-sdk/blob/master/src/rp2_common/pico_fix/rp2040_usb_device_enumeration/rp2040_usb_device_enumeration.c -// According to errata RP2040-E5: -// "It is safe (and inexpensive) to enable the software workaround even when using versions of RP2040 -// which include the fix in hardware." -// So let us always use the software fix. -func fixRP2040UsbDeviceEnumeration() { - // After coming out of reset, the hardware expects 800us of LS_J (linestate J) time - // before it will move to the connected state. However on a hub that broadcasts packets - // for other devices this isn't the case. The plan here is to wait for the end of the bus - // reset, force an LS_J for 1ms and then switch control back to the USB phy. Unfortunately - // this requires us to use GPIO15 as there is no other way to force the input path. - // We only need to force DP as DM can be left at zero. It will be gated off by GPIO - // logic if it isn't func selected. - - // Wait SE0 phase will call force ls_j phase which will call finish phase - hw_enumeration_fix_wait_se0() -} - -func hw_enumeration_fix_wait_se0() { - // Wait for SE0 to end (i.e. the host to stop resetting). This reset can last quite long. - // 10-15ms so we are going to set a timer callback. - - // if timer pool disabled, or no timer available, have to busy wait. - hw_enumeration_fix_busy_wait_se0() -} - -const ( - LS_SE0 = 0b00 - LS_J = 0b01 - LS_K = 0b10 - LS_SE1 = 0b11 -) - -const ( - dp = 15 -) - -var ( - gpioCtrlPrev uint32 - padCtrlPrev uint32 -) - -func hw_enumeration_fix_busy_wait_se0() { - for ((rp.USBCTRL_REGS.SIE_STATUS.Get() & rp.USBCTRL_REGS_SIE_STATUS_LINE_STATE_Msk) >> rp.USBCTRL_REGS_SIE_STATUS_LINE_STATE_Pos) == LS_SE0 { - } - - // Now force LS_J (next stage of fix) - hw_enumeration_fix_force_ls_j() -} - -func hw_enumeration_fix_force_ls_j() { - // DM must be 0 for this to work. This is true if it is selected - // to any other function. fn 8 on this pin is only for debug so shouldn't - // be selected - - // Before changing any pin state, take a copy of the current gpio control register - gpioCtrlPrev = ioBank0.io[dp].ctrl.Get() - // Also take a copy of the pads register - padCtrlPrev = padsBank0.io[dp].Get() - - // Enable bus keep and force pin to tristate, so USB DP muxing doesn't affect - // pin state - padsBank0.io[dp].SetBits(rp.PADS_BANK0_GPIO0_PUE | rp.PADS_BANK0_GPIO0_PDE) - ioBank0.io[dp].ctrl.ReplaceBits(rp.IO_BANK0_GPIO0_CTRL_OEOVER_DISABLE, rp.IO_BANK0_GPIO0_CTRL_OEOVER_Msk>>rp.IO_BANK0_GPIO0_CTRL_OEOVER_Pos, rp.IO_BANK0_GPIO0_CTRL_OEOVER_Pos) - - // Select function 8 (USB debug muxing) without disturbing other controls - ioBank0.io[dp].ctrl.ReplaceBits(8, rp.IO_BANK0_GPIO0_CTRL_FUNCSEL_Msk>>rp.IO_BANK0_GPIO0_CTRL_FUNCSEL_Pos, rp.IO_BANK0_GPIO0_CTRL_FUNCSEL_Pos) - - // J state is a differential 1 for a full speed device so - // DP = 1 and DM = 0. Don't actually need to set DM low as it - // is already gated assuming it isn't funcseld. - ioBank0.io[dp].ctrl.ReplaceBits(rp.IO_BANK0_GPIO1_CTRL_INOVER_HIGH, rp.IO_BANK0_GPIO1_CTRL_INOVER_Msk>>rp.IO_BANK0_GPIO1_CTRL_INOVER_Pos, rp.IO_BANK0_GPIO1_CTRL_INOVER_Pos) - - // Force PHY pull up to stay before switching away from the phy - rp.USBCTRL_REGS.USBPHY_DIRECT.SetBits(rp.USBCTRL_REGS_USBPHY_DIRECT_DP_PULLUP_EN) - rp.USBCTRL_REGS.USBPHY_DIRECT_OVERRIDE.SetBits(rp.USBCTRL_REGS_USBPHY_DIRECT_OVERRIDE_DP_PULLUP_EN_OVERRIDE_EN) - - // Switch to GPIO phy with LS_J forced - rp.USBCTRL_REGS.USB_MUXING.Set(rp.USBCTRL_REGS_USB_MUXING_TO_DIGITAL_PAD | rp.USBCTRL_REGS_USB_MUXING_SOFTCON) - - // LS_J is now forced but while loop to wait ~800us here just to check - waitCycles(25000) - - // if timer pool disabled, or no timer available, have to busy wait. - hw_enumeration_fix_finish() - -} - -func hw_enumeration_fix_finish() { - // Should think we are connected now - for (rp.USBCTRL_REGS.SIE_STATUS.Get() & rp.USBCTRL_REGS_SIE_STATUS_CONNECTED) != rp.USBCTRL_REGS_SIE_STATUS_CONNECTED { - } - - // Switch back to USB phy - rp.USBCTRL_REGS.USB_MUXING.Set(rp.USBCTRL_REGS_USB_MUXING_TO_PHY | rp.USBCTRL_REGS_USB_MUXING_SOFTCON) - - // Get rid of DP pullup override - rp.USBCTRL_REGS.USBPHY_DIRECT_OVERRIDE.ClearBits(rp.USBCTRL_REGS_USBPHY_DIRECT_OVERRIDE_DP_PULLUP_EN_OVERRIDE_EN) - - // Finally, restore the gpio ctrl value back to GPIO15 - ioBank0.io[dp].ctrl.Set(gpioCtrlPrev) - // Restore the pad ctrl value - padsBank0.io[dp].Set(padCtrlPrev) -} - -func waitCycles(n int) { - for n > 0 { - arm.Asm("nop") - n-- - } -} diff --git a/emb/machine/machine_rp2350_rom.go b/emb/machine/machine_rp2350_rom.go deleted file mode 100644 index 665464a..0000000 --- a/emb/machine/machine_rp2350_rom.go +++ /dev/null @@ -1,560 +0,0 @@ -//go:build tinygo && rp2350 - -package machine - -import ( - "runtime/interrupt" - "unsafe" -) - -/* -typedef unsigned char uint8_t; -typedef unsigned short uint16_t; -typedef unsigned long uint32_t; -typedef unsigned long size_t; -typedef unsigned long uintptr_t; -typedef long int intptr_t; - -typedef const volatile uint16_t io_ro_16; -typedef const volatile uint32_t io_ro_32; -typedef volatile uint16_t io_rw_16; -typedef volatile uint32_t io_rw_32; -typedef volatile uint32_t io_wo_32; - -#define false 0 -#define true 1 -typedef int bool; - -#define ram_func __attribute__((section(".ramfuncs"),noinline)) - -typedef void (*flash_exit_xip_fn)(void); -typedef void (*flash_flush_cache_fn)(void); -typedef void (*flash_connect_internal_fn)(void); -typedef void (*flash_range_erase_fn)(uint32_t, size_t, uint32_t, uint16_t); -typedef void (*flash_range_program_fn)(uint32_t, const uint8_t*, size_t); -static inline __attribute__((always_inline)) void __compiler_memory_barrier(void) { - __asm__ volatile ("" : : : "memory"); -} - -// https://datasheets.raspberrypi.com/rp2350/rp2350-datasheet.pdf -// 13.9. Predefined OTP Data Locations -// OTP_DATA: FLASH_DEVINFO Register - -#define OTP_DATA_FLASH_DEVINFO_CS0_SIZE_BITS 0x0F00 -#define OTP_DATA_FLASH_DEVINFO_CS0_SIZE_LSB 8 -#define OTP_DATA_FLASH_DEVINFO_CS1_SIZE_BITS 0xF000 -#define OTP_DATA_FLASH_DEVINFO_CS1_SIZE_LSB 12 - - -// https://github.com/raspberrypi/pico-sdk -// src/rp2350/hardware_regs/include/hardware/regs/addressmap.h - -#define REG_ALIAS_RW_BITS (0x0 << 12) -#define REG_ALIAS_XOR_BITS (0x1 << 12) -#define REG_ALIAS_SET_BITS (0x2 << 12) -#define REG_ALIAS_CLR_BITS (0x3 << 12) - -#define XIP_BASE 0x10000000 -#define XIP_QMI_BASE 0x400d0000 -#define IO_QSPI_BASE 0x40030000 -#define BOOTRAM_BASE 0x400e0000 - - -// https://github.com/raspberrypi/pico-sdk -// src/rp2_common/hardware_base/include/hardware/address_mapped.h - -#define hw_alias_check_addr(addr) ((uintptr_t)(addr)) -#define hw_set_alias_untyped(addr) ((void *)(REG_ALIAS_SET_BITS + hw_alias_check_addr(addr))) -#define hw_clear_alias_untyped(addr) ((void *)(REG_ALIAS_CLR_BITS + hw_alias_check_addr(addr))) -#define hw_xor_alias_untyped(addr) ((void *)(REG_ALIAS_XOR_BITS + hw_alias_check_addr(addr))) - -__attribute__((always_inline)) -static void hw_set_bits(io_rw_32 *addr, uint32_t mask) { - *(io_rw_32 *) hw_set_alias_untyped((volatile void *) addr) = mask; -} - -__attribute__((always_inline)) -static void hw_clear_bits(io_rw_32 *addr, uint32_t mask) { - *(io_rw_32 *) hw_clear_alias_untyped((volatile void *) addr) = mask; -} - -__attribute__((always_inline)) -static void hw_xor_bits(io_rw_32 *addr, uint32_t mask) { - *(io_rw_32 *) hw_xor_alias_untyped((volatile void *) addr) = mask; -} - -__attribute__((always_inline)) -static void hw_write_masked(io_rw_32 *addr, uint32_t values, uint32_t write_mask) { - hw_xor_bits(addr, (*addr ^ values) & write_mask); -} - - -// https://github.com/raspberrypi/pico-sdk -// src/rp2_common/pico_platform_compiler/include/pico/platform/compiler.h - -#define pico_default_asm_volatile(...) __asm volatile (".syntax unified\n" __VA_ARGS__) - - -// https://github.com/raspberrypi/pico-sdk -// src/rp2350/pico_platform/include/pico/platform.h - -static bool pico_processor_state_is_nonsecure(void) { -// // todo add a define to disable NS checking at all? -// // IDAU-Exempt addresses return S=1 when tested in the Secure state, -// // whereas executing a tt in the NonSecure state will always return S=0. -// uint32_t tt; -// pico_default_asm_volatile ( -// "movs %0, #0\n" -// "tt %0, %0\n" -// : "=r" (tt) : : "cc" -// ); -// return !(tt & (1u << 22)); - - return false; -} - - -// https://github.com/raspberrypi/pico-sdk -// src/rp2_common/pico_bootrom/include/pico/bootrom_constants.h - -// RP2040 & RP2350 -#define ROM_DATA_SOFTWARE_GIT_REVISION ROM_TABLE_CODE('G', 'R') -#define ROM_FUNC_FLASH_ENTER_CMD_XIP ROM_TABLE_CODE('C', 'X') -#define ROM_FUNC_FLASH_EXIT_XIP ROM_TABLE_CODE('E', 'X') -#define ROM_FUNC_FLASH_FLUSH_CACHE ROM_TABLE_CODE('F', 'C') -#define ROM_FUNC_CONNECT_INTERNAL_FLASH ROM_TABLE_CODE('I', 'F') -#define ROM_FUNC_FLASH_RANGE_ERASE ROM_TABLE_CODE('R', 'E') -#define ROM_FUNC_FLASH_RANGE_PROGRAM ROM_TABLE_CODE('R', 'P') - -// RP2350 only -#define ROM_FUNC_PICK_AB_PARTITION ROM_TABLE_CODE('A', 'B') -#define ROM_FUNC_CHAIN_IMAGE ROM_TABLE_CODE('C', 'I') -#define ROM_FUNC_EXPLICIT_BUY ROM_TABLE_CODE('E', 'B') -#define ROM_FUNC_FLASH_RUNTIME_TO_STORAGE_ADDR ROM_TABLE_CODE('F', 'A') -#define ROM_DATA_FLASH_DEVINFO16_PTR ROM_TABLE_CODE('F', 'D') -#define ROM_FUNC_FLASH_OP ROM_TABLE_CODE('F', 'O') -#define ROM_FUNC_GET_B_PARTITION ROM_TABLE_CODE('G', 'B') -#define ROM_FUNC_GET_PARTITION_TABLE_INFO ROM_TABLE_CODE('G', 'P') -#define ROM_FUNC_GET_SYS_INFO ROM_TABLE_CODE('G', 'S') -#define ROM_FUNC_GET_UF2_TARGET_PARTITION ROM_TABLE_CODE('G', 'U') -#define ROM_FUNC_LOAD_PARTITION_TABLE ROM_TABLE_CODE('L', 'P') -#define ROM_FUNC_OTP_ACCESS ROM_TABLE_CODE('O', 'A') -#define ROM_DATA_PARTITION_TABLE_PTR ROM_TABLE_CODE('P', 'T') -#define ROM_FUNC_FLASH_RESET_ADDRESS_TRANS ROM_TABLE_CODE('R', 'A') -#define ROM_FUNC_REBOOT ROM_TABLE_CODE('R', 'B') -#define ROM_FUNC_SET_ROM_CALLBACK ROM_TABLE_CODE('R', 'C') -#define ROM_FUNC_SECURE_CALL ROM_TABLE_CODE('S', 'C') -#define ROM_FUNC_SET_NS_API_PERMISSION ROM_TABLE_CODE('S', 'P') -#define ROM_FUNC_BOOTROM_STATE_RESET ROM_TABLE_CODE('S', 'R') -#define ROM_FUNC_SET_BOOTROM_STACK ROM_TABLE_CODE('S', 'S') -#define ROM_DATA_SAVED_XIP_SETUP_FUNC_PTR ROM_TABLE_CODE('X', 'F') -#define ROM_FUNC_FLASH_SELECT_XIP_READ_MODE ROM_TABLE_CODE('X', 'M') -#define ROM_FUNC_VALIDATE_NS_BUFFER ROM_TABLE_CODE('V', 'B') - -#define BOOTSEL_FLAG_GPIO_PIN_SPECIFIED 0x20 - -#define BOOTROM_FUNC_TABLE_OFFSET 0x14 - -// todo remove this (or #ifdef it for A1/A2) -#define BOOTROM_IS_A2() ((*(volatile uint8_t *)0x13) == 2) -#define BOOTROM_WELL_KNOWN_PTR_SIZE (BOOTROM_IS_A2() ? 2 : 4) - -#define BOOTROM_VTABLE_OFFSET 0x00 -#define BOOTROM_TABLE_LOOKUP_OFFSET (BOOTROM_FUNC_TABLE_OFFSET + BOOTROM_WELL_KNOWN_PTR_SIZE) - - -// https://github.com/raspberrypi/pico-sdk -// src/common/boot_picoboot_headers/include/boot/picoboot_constants.h - -// values 0-7 are secure/non-secure -#define REBOOT2_FLAG_REBOOT_TYPE_NORMAL 0x0 // param0 = diagnostic partition -#define REBOOT2_FLAG_REBOOT_TYPE_BOOTSEL 0x2 // param0 = bootsel_flags, param1 = gpio_config -#define REBOOT2_FLAG_REBOOT_TYPE_RAM_IMAGE 0x3 // param0 = image_base, param1 = image_end -#define REBOOT2_FLAG_REBOOT_TYPE_FLASH_UPDATE 0x4 // param0 = update_base - -#define REBOOT2_FLAG_NO_RETURN_ON_SUCCESS 0x100 - -#define RT_FLAG_FUNC_ARM_SEC 0x0004 -#define RT_FLAG_FUNC_ARM_NONSEC 0x0010 -#define RT_FLAG_DATA 0x0040 - - -// https://github.com/raspberrypi/pico-sdk -// src/rp2_common/pico_bootrom/include/pico/bootrom.h - -#define ROM_TABLE_CODE(c1, c2) ((c1) | ((c2) << 8)) - -typedef void *(*rom_table_lookup_fn)(uint32_t code, uint32_t mask); - -__attribute__((always_inline)) -static void *rom_func_lookup_inline(uint32_t code) { - rom_table_lookup_fn rom_table_lookup = (rom_table_lookup_fn) (uintptr_t)*(uint16_t*)(BOOTROM_TABLE_LOOKUP_OFFSET); - if (pico_processor_state_is_nonsecure()) { - return rom_table_lookup(code, RT_FLAG_FUNC_ARM_NONSEC); - } else { - return rom_table_lookup(code, RT_FLAG_FUNC_ARM_SEC); - } -} - -__attribute__((always_inline)) -static void *rom_data_lookup_inline(uint32_t code) { - rom_table_lookup_fn rom_table_lookup = (rom_table_lookup_fn) (uintptr_t)*(uint16_t*)(BOOTROM_TABLE_LOOKUP_OFFSET); - return rom_table_lookup(code, RT_FLAG_DATA); -} - -typedef int (*rom_reboot_fn)(uint32_t flags, uint32_t delay_ms, uint32_t p0, uint32_t p1); - -__attribute__((always_inline)) -int rom_reboot(uint32_t flags, uint32_t delay_ms, uint32_t p0, uint32_t p1) { - rom_reboot_fn func = (rom_reboot_fn) rom_func_lookup_inline(ROM_FUNC_REBOOT); - return func(flags, delay_ms, p0, p1); -} - - -// https://github.com/raspberrypi/pico-sdk -// src/rp2_common/pico_bootrom/bootrom.c - -void reset_usb_boot(uint32_t usb_activity_gpio_pin_mask, uint32_t disable_interface_mask) { - uint32_t flags = disable_interface_mask; - if (usb_activity_gpio_pin_mask) { - flags |= BOOTSEL_FLAG_GPIO_PIN_SPECIFIED; - // the parameter is actually the gpio number, but we only care if BOOTSEL_FLAG_GPIO_PIN_SPECIFIED - usb_activity_gpio_pin_mask = (uint32_t)__builtin_ctz(usb_activity_gpio_pin_mask); - } - rom_reboot(REBOOT2_FLAG_REBOOT_TYPE_BOOTSEL | REBOOT2_FLAG_NO_RETURN_ON_SUCCESS, 10, flags, usb_activity_gpio_pin_mask); - __builtin_unreachable(); -} - - -// https://github.com/raspberrypi/pico-sdk -// src/rp2350/hardware_regs/include/hardware/regs/qmi.h - -#define QMI_DIRECT_CSR_EN_BITS 0x00000001 -#define QMI_DIRECT_CSR_RXEMPTY_BITS 0x00010000 -#define QMI_DIRECT_CSR_TXFULL_BITS 0x00000400 -#define QMI_M1_WFMT_RESET 0x00001000 -#define QMI_M1_WCMD_RESET 0x0000a002 - - -// https://github.com/raspberrypi/pico-sdk -// src/rp2350/hardware_regs/include/hardware/regs/io_qspi.h - -#define IO_QSPI_GPIO_QSPI_SS_CTRL_OUTOVER_BITS 0x00003000 -#define IO_QSPI_GPIO_QSPI_SS_CTRL_OUTOVER_LSB 12 -#define IO_QSPI_GPIO_QSPI_SS_CTRL_OUTOVER_VALUE_LOW 0x2 -#define IO_QSPI_GPIO_QSPI_SS_CTRL_OUTOVER_VALUE_HIGH 0x3 - - -// https://github.com/raspberrypi/pico-sdk -// src/rp2350/hardware_structs/include/hardware/structs/io_qspi.h - -typedef struct { - io_rw_32 inte; // IO_QSPI_PROC0_INTE - io_rw_32 intf; // IO_QSPI_PROC0_INTF - io_ro_32 ints; // IO_QSPI_PROC0_INTS -} io_qspi_irq_ctrl_hw_t; - -typedef struct { - io_ro_32 status; // IO_QSPI_GPIO_QSPI_SCLK_STATUS - io_rw_32 ctrl; // IO_QSPI_GPIO_QSPI_SCLK_CTRL -} io_qspi_status_ctrl_hw_t; - -typedef struct { - io_ro_32 usbphy_dp_status; // IO_QSPI_USBPHY_DP_STATUS - io_rw_32 usbphy_dp_ctrl; // IO_QSPI_USBPHY_DP_CTRL - io_ro_32 usbphy_dm_status; // IO_QSPI_USBPHY_DM_STATUS - io_rw_32 usbphy_dm_ctrl; // IO_QSPI_USBPHY_DM_CTRL - io_qspi_status_ctrl_hw_t io[6]; - uint32_t _pad0[112]; - io_ro_32 irqsummary_proc0_secure; // IO_QSPI_IRQSUMMARY_PROC0_SECURE - io_ro_32 irqsummary_proc0_nonsecure; // IO_QSPI_IRQSUMMARY_PROC0_NONSECURE - io_ro_32 irqsummary_proc1_secure; // IO_QSPI_IRQSUMMARY_PROC1_SECURE - io_ro_32 irqsummary_proc1_nonsecure; // IO_QSPI_IRQSUMMARY_PROC1_NONSECURE - io_ro_32 irqsummary_dormant_wake_secure; // IO_QSPI_IRQSUMMARY_DORMANT_WAKE_SECURE - io_ro_32 irqsummary_dormant_wake_nonsecure; // IO_QSPI_IRQSUMMARY_DORMANT_WAKE_NONSECURE - io_rw_32 intr; // IO_QSPI_INTR - - union { - struct { - io_qspi_irq_ctrl_hw_t proc0_irq_ctrl; - io_qspi_irq_ctrl_hw_t proc1_irq_ctrl; - io_qspi_irq_ctrl_hw_t dormant_wake_irq_ctrl; - }; - io_qspi_irq_ctrl_hw_t irq_ctrl[3]; - }; -} io_qspi_hw_t; - -#define io_qspi_hw ((io_qspi_hw_t *)IO_QSPI_BASE) - - -// https://github.com/raspberrypi/pico-sdk -// src/rp2350/hardware_structs/include/hardware/structs/qmi.h - -typedef struct { - io_rw_32 timing; // QMI_M0_TIMING - io_rw_32 rfmt; // QMI_M0_RFMT - io_rw_32 rcmd; // QMI_M0_RCMD - io_rw_32 wfmt; // QMI_M0_WFMT - io_rw_32 wcmd; // QMI_M0_WCMD -} qmi_mem_hw_t; - -typedef struct { - io_rw_32 direct_csr; // QMI_DIRECT_CSR - io_wo_32 direct_tx; // QMI_DIRECT_TX - io_ro_32 direct_rx; // QMI_DIRECT_RX - qmi_mem_hw_t m[2]; - io_rw_32 atrans[8]; // QMI_ATRANS0 -} qmi_hw_t; - -#define qmi_hw ((qmi_hw_t *)XIP_QMI_BASE) - - -// https://github.com/raspberrypi/pico-sdk -// src/rp2_common/hardware_xip_cache/include/hardware/xip_cache.h - -// Noop unless using XIP Cache-as-SRAM -// Non-noop version in src/rp2_common/hardware_xip_cache/xip_cache.c -static inline void xip_cache_clean_all(void) {} - - -// https://github.com/raspberrypi/pico-sdk -// src/rp2_common/hardware_flash/include/hardware/flash.h - -#define FLASH_PAGE_SIZE (1u << 8) -#define FLASH_SECTOR_SIZE (1u << 12) -#define FLASH_BLOCK_SIZE (1u << 16) - - -// https://github.com/raspberrypi/pico-sdk -// src/rp2_common/hardware_flash/flash.c - -#define BOOT2_SIZE_WORDS 64 -#define FLASH_BLOCK_ERASE_CMD 0xd8 - -static uint32_t boot2_copyout[BOOT2_SIZE_WORDS]; -static bool boot2_copyout_valid = false; - -static ram_func void flash_init_boot2_copyout(void) { - if (boot2_copyout_valid) - return; - for (int i = 0; i < BOOT2_SIZE_WORDS; ++i) - boot2_copyout[i] = ((uint32_t *)BOOTRAM_BASE)[i]; - __compiler_memory_barrier(); - boot2_copyout_valid = true; -} - -static ram_func void flash_enable_xip_via_boot2(void) { - ((void (*)(void))((intptr_t)boot2_copyout+1))(); -} - -// This is a static symbol because the layout of FLASH_DEVINFO is liable to change from device to -// device, so fields must have getters/setters. -static io_rw_16 * ram_func flash_devinfo_ptr(void) { - // Note the lookup returns a pointer to a 32-bit pointer literal in the ROM - io_rw_16 **p = (io_rw_16 **) rom_data_lookup_inline(ROM_DATA_FLASH_DEVINFO16_PTR); - return *p; -} - -// This is a RAM function because may be called during flash programming to enable save/restore of -// QMI window 1 registers on RP2350: -uint8_t ram_func flash_devinfo_get_cs_size(uint8_t cs) { - io_ro_16 *devinfo = (io_ro_16 *) flash_devinfo_ptr(); - if (cs == 0u) { - return (uint8_t) ( - (*devinfo & OTP_DATA_FLASH_DEVINFO_CS0_SIZE_BITS) >> OTP_DATA_FLASH_DEVINFO_CS0_SIZE_LSB - ); - } else { - return (uint8_t) ( - (*devinfo & OTP_DATA_FLASH_DEVINFO_CS1_SIZE_BITS) >> OTP_DATA_FLASH_DEVINFO_CS1_SIZE_LSB - ); - } -} - -// This is specifically for saving/restoring the registers modified by RP2350 -// flash_exit_xip() ROM func, not the entirety of the QMI window state. -typedef struct flash_rp2350_qmi_save_state { - uint32_t timing; - uint32_t rcmd; - uint32_t rfmt; -} flash_rp2350_qmi_save_state_t; - -static ram_func void flash_rp2350_save_qmi_cs1(flash_rp2350_qmi_save_state_t *state) { - state->timing = qmi_hw->m[1].timing; - state->rcmd = qmi_hw->m[1].rcmd; - state->rfmt = qmi_hw->m[1].rfmt; -} - -static ram_func void flash_rp2350_restore_qmi_cs1(const flash_rp2350_qmi_save_state_t *state) { - if (flash_devinfo_get_cs_size(1) == 0) { - // Case 1: The RP2350 ROM sets QMI to a clean (03h read) configuration - // during flash_exit_xip(), even though when CS1 is not enabled via - // FLASH_DEVINFO it does not issue an XIP exit sequence to CS1. In - // this case, restore the original register config for CS1 as it is - // still the correct config. - qmi_hw->m[1].timing = state->timing; - qmi_hw->m[1].rcmd = state->rcmd; - qmi_hw->m[1].rfmt = state->rfmt; - } else { - // Case 2: If RAM is attached to CS1, and the ROM has issued an XIP - // exit sequence to it, then the ROM re-initialisation of the QMI - // registers has actually not gone far enough. The old XIP write mode - // is no longer valid when the QSPI RAM is returned to a serial - // command state. Restore the default 02h serial write command config. - qmi_hw->m[1].wfmt = QMI_M1_WFMT_RESET; - qmi_hw->m[1].wcmd = QMI_M1_WCMD_RESET; - } -} - -void ram_func flash_cs_force(bool high) { - uint32_t field_val = high ? - IO_QSPI_GPIO_QSPI_SS_CTRL_OUTOVER_VALUE_HIGH : - IO_QSPI_GPIO_QSPI_SS_CTRL_OUTOVER_VALUE_LOW; - hw_write_masked(&io_qspi_hw->io[1].ctrl, - field_val << IO_QSPI_GPIO_QSPI_SS_CTRL_OUTOVER_LSB, - IO_QSPI_GPIO_QSPI_SS_CTRL_OUTOVER_BITS - ); -} - -// Adapted from flash_range_program() -void ram_func flash_range_write(uint32_t offset, const uint8_t *data, size_t count) { - flash_connect_internal_fn flash_connect_internal_func = (flash_connect_internal_fn)rom_func_lookup_inline(ROM_FUNC_CONNECT_INTERNAL_FLASH); - flash_exit_xip_fn flash_exit_xip_func = (flash_exit_xip_fn)rom_func_lookup_inline(ROM_FUNC_FLASH_EXIT_XIP); - flash_range_program_fn flash_range_program_func = (flash_range_program_fn)rom_func_lookup_inline(ROM_FUNC_FLASH_RANGE_PROGRAM); - flash_flush_cache_fn flash_flush_cache_func = (flash_flush_cache_fn)rom_func_lookup_inline(ROM_FUNC_FLASH_FLUSH_CACHE); - flash_init_boot2_copyout(); - xip_cache_clean_all(); - flash_rp2350_qmi_save_state_t qmi_save; - flash_rp2350_save_qmi_cs1(&qmi_save); - - __compiler_memory_barrier(); - - flash_connect_internal_func(); - flash_exit_xip_func(); - flash_range_program_func(offset, data, count); - flash_flush_cache_func(); // Note this is needed to remove CSn IO force as well as cache flushing - flash_enable_xip_via_boot2(); - flash_rp2350_restore_qmi_cs1(&qmi_save); -} - -// Adapted from flash_range_erase() -void ram_func flash_erase_blocks(uint32_t offset, size_t count) { - flash_connect_internal_fn flash_connect_internal_func = (flash_connect_internal_fn)rom_func_lookup_inline(ROM_FUNC_CONNECT_INTERNAL_FLASH); - flash_exit_xip_fn flash_exit_xip_func = (flash_exit_xip_fn)rom_func_lookup_inline(ROM_FUNC_FLASH_EXIT_XIP); - flash_range_erase_fn flash_range_erase_func = (flash_range_erase_fn)rom_func_lookup_inline(ROM_FUNC_FLASH_RANGE_ERASE); - flash_flush_cache_fn flash_flush_cache_func = (flash_flush_cache_fn)rom_func_lookup_inline(ROM_FUNC_FLASH_FLUSH_CACHE); - flash_init_boot2_copyout(); - // Commit any pending writes to external RAM, to avoid losing them in the subsequent flush: - xip_cache_clean_all(); - flash_rp2350_qmi_save_state_t qmi_save; - flash_rp2350_save_qmi_cs1(&qmi_save); - - // No flash accesses after this point - __compiler_memory_barrier(); - - flash_connect_internal_func(); - flash_exit_xip_func(); - flash_range_erase_func(offset, count, FLASH_BLOCK_SIZE, FLASH_BLOCK_ERASE_CMD); - flash_flush_cache_func(); // Note this is needed to remove CSn IO force as well as cache flushing - flash_enable_xip_via_boot2(); - flash_rp2350_restore_qmi_cs1(&qmi_save); -} - -void ram_func flash_do_cmd(const uint8_t *txbuf, uint8_t *rxbuf, size_t count) { - flash_connect_internal_fn flash_connect_internal_func = (flash_connect_internal_fn)rom_func_lookup_inline(ROM_FUNC_CONNECT_INTERNAL_FLASH); - flash_exit_xip_fn flash_exit_xip_func = (flash_exit_xip_fn)rom_func_lookup_inline(ROM_FUNC_FLASH_EXIT_XIP); - flash_flush_cache_fn flash_flush_cache_func = (flash_flush_cache_fn)rom_func_lookup_inline(ROM_FUNC_FLASH_FLUSH_CACHE); - flash_init_boot2_copyout(); - xip_cache_clean_all(); - - flash_rp2350_qmi_save_state_t qmi_save; - flash_rp2350_save_qmi_cs1(&qmi_save); - - __compiler_memory_barrier(); - flash_connect_internal_func(); - flash_exit_xip_func(); - - flash_cs_force(0); - size_t tx_remaining = count; - size_t rx_remaining = count; - - // QMI version -- no need to bound FIFO contents as QMI stalls on full DIRECT_RX. - hw_set_bits(&qmi_hw->direct_csr, QMI_DIRECT_CSR_EN_BITS); - while (tx_remaining || rx_remaining) { - uint32_t flags = qmi_hw->direct_csr; - bool can_put = !(flags & QMI_DIRECT_CSR_TXFULL_BITS); - bool can_get = !(flags & QMI_DIRECT_CSR_RXEMPTY_BITS); - if (can_put && tx_remaining) { - qmi_hw->direct_tx = *txbuf++; - --tx_remaining; - } - if (can_get && rx_remaining) { - *rxbuf++ = (uint8_t)qmi_hw->direct_rx; - --rx_remaining; - } - } - hw_clear_bits(&qmi_hw->direct_csr, QMI_DIRECT_CSR_EN_BITS); - - flash_cs_force(1); - - flash_flush_cache_func(); - flash_enable_xip_via_boot2(); - flash_rp2350_restore_qmi_cs1(&qmi_save); -} - -*/ -import "C" - -func enterBootloader() { - C.reset_usb_boot(0, 0) -} - -func doFlashCommand(tx []byte, rx []byte) error { - if len(tx) != len(rx) { - return errFlashInvalidWriteLength - } - - C.flash_do_cmd( - (*C.uint8_t)(unsafe.Pointer(&tx[0])), - (*C.uint8_t)(unsafe.Pointer(&rx[0])), - C.ulong(len(tx))) - - return nil -} - -// Flash related code -const memoryStart = C.XIP_BASE // memory start for purpose of erase - -func (f flashBlockDevice) writeAt(p []byte, off int64) (n int, err error) { - if writeAddress(off)+uintptr(C.XIP_BASE) > FlashDataEnd() { - return 0, errFlashCannotWritePastEOF - } - - state := interrupt.Disable() - defer interrupt.Restore(state) - - // rp2350 writes to offset, not actual address - // e.g. real address 0x10003000 is written to at - // 0x00003000 - address := writeAddress(off) - padded := flashPad(p, int(f.WriteBlockSize())) - - C.flash_range_write(C.uint32_t(address), - (*C.uint8_t)(unsafe.Pointer(&padded[0])), - C.ulong(len(padded))) - - return len(padded), nil -} - -func (f flashBlockDevice) eraseBlocks(start, length int64) error { - address := writeAddress(start * f.EraseBlockSize()) - if address+uintptr(C.XIP_BASE) > FlashDataEnd() { - return errFlashCannotErasePastEOF - } - - state := interrupt.Disable() - defer interrupt.Restore(state) - - C.flash_erase_blocks(C.uint32_t(address), C.ulong(length*f.EraseBlockSize())) - - return nil -} diff --git a/emb/machine/machine_rp2350_usb.go b/emb/machine/machine_rp2350_usb.go deleted file mode 100644 index ca09262..0000000 --- a/emb/machine/machine_rp2350_usb.go +++ /dev/null @@ -1,151 +0,0 @@ -//go:build rp2350 - -package machine - -import ( - "device/rp" - "machine/usb" - "runtime/interrupt" -) - -// Configure the USB peripheral. The config is here for compatibility with the UART interface. -func (dev *USBDevice) Configure(config UARTConfig) { - // Reset usb controller - resetBlock(rp.RESETS_RESET_USBCTRL) - unresetBlockWait(rp.RESETS_RESET_USBCTRL) - - // Clear any previous state in dpram just in case - _usbDPSRAM.clear() - - // Enable USB interrupt at processor - rp.USB.INTE.Set(0) - intr := interrupt.New(rp.IRQ_USBCTRL_IRQ, handleUSBIRQ) - intr.SetPriority(0x00) - intr.Enable() - irqSet(rp.IRQ_USBCTRL_IRQ, true) - - // Mux the controller to the onboard usb phy - rp.USB.USB_MUXING.Set(rp.USB_USB_MUXING_TO_PHY | rp.USB_USB_MUXING_SOFTCON) - - // Force VBUS detect so the device thinks it is plugged into a host - rp.USB.USB_PWR.Set(rp.USB_USB_PWR_VBUS_DETECT | rp.USB_USB_PWR_VBUS_DETECT_OVERRIDE_EN) - - // Enable the USB controller in device mode. - rp.USB.MAIN_CTRL.Set(rp.USB_MAIN_CTRL_CONTROLLER_EN) - - // Enable an interrupt per EP0 transaction - rp.USB.SIE_CTRL.Set(rp.USB_SIE_CTRL_EP0_INT_1BUF) - - // Enable interrupts for when a buffer is done, when the bus is reset, - // and when a setup packet is received - rp.USB.INTE.Set(rp.USB_INTE_BUFF_STATUS | - rp.USB_INTE_BUS_RESET | - rp.USB_INTE_SETUP_REQ) - - // Present full speed device by enabling pull up on DP - rp.USB.SIE_CTRL.SetBits(rp.USB_SIE_CTRL_PULLUP_EN) - - // 12.7.2 Disable phy isolation - rp.USB.SetMAIN_CTRL_PHY_ISO(0x0) -} - -func handleUSBIRQ(intr interrupt.Interrupt) { - status := rp.USB.INTS.Get() - - // Setup packet received - if (status & rp.USB_INTS_SETUP_REQ) > 0 { - rp.USB.SIE_STATUS.Set(rp.USB_SIE_STATUS_SETUP_REC) - setup := usb.NewSetup(_usbDPSRAM.setupBytes()) - - ok := false - if (setup.BmRequestType & usb.REQUEST_TYPE) == usb.REQUEST_STANDARD { - // Standard Requests - ok = handleStandardSetup(setup) - } else { - // Class Interface Requests - if setup.WIndex < uint16(len(usbSetupHandler)) && usbSetupHandler[setup.WIndex] != nil { - ok = usbSetupHandler[setup.WIndex](setup) - } - } - - if !ok { - // Stall endpoint? - USBDev.SetStallEPIn(0) - } - - } - - // Buffer status, one or more buffers have completed - if (status & rp.USB_INTS_BUFF_STATUS) > 0 { - if sendOnEP0DATADONE.offset > 0 { - ep := uint32(0) - data := sendOnEP0DATADONE.data - count := len(data) - sendOnEP0DATADONE.offset - if ep == 0 && count > usb.EndpointPacketSize { - count = usb.EndpointPacketSize - } - - sendViaEPIn(ep, data[sendOnEP0DATADONE.offset:], count) - sendOnEP0DATADONE.offset += count - if sendOnEP0DATADONE.offset == len(data) { - sendOnEP0DATADONE.offset = 0 - } - } - - s2 := rp.USB.BUFF_STATUS.Get() - - // OUT (PC -> rp2350) - for i := 0; i < 16; i++ { - if s2&(1<<(i*2+1)) > 0 { - buf := handleEndpointRx(uint32(i)) - if usbRxHandler[i] == nil || usbRxHandler[i](buf) { - AckUsbOutTransfer(uint32(i)) - } - } - } - - // IN (rp2350 -> PC) - for i := 0; i < 16; i++ { - if s2&(1<<(i*2)) > 0 { - if usbTxHandler[i] != nil { - usbTxHandler[i]() - } - } - } - - rp.USB.BUFF_STATUS.Set(s2) - } - - // Bus is reset - if (status & rp.USB_INTS_BUS_RESET) > 0 { - rp.USB.SIE_STATUS.Set(rp.USB_SIE_STATUS_BUS_RESET) - //fixRP2040UsbDeviceEnumeration() - - rp.USB.ADDR_ENDP.Set(0) - initEndpoint(0, usb.ENDPOINT_TYPE_CONTROL) - } -} - -func handleUSBSetAddress(setup usb.Setup) bool { - // Using 570μs timeout which is exactly the same as SAMD21. - const ackTimeout = 570 - - rp.USB.SIE_STATUS.Set(rp.USB_SIE_STATUS_ACK_REC) - sendUSBPacket(0, []byte{}, 0) - - // Wait for transfer to complete with a timeout. - t := timer.timeElapsed() - for (rp.USB.SIE_STATUS.Get() & rp.USB_SIE_STATUS_ACK_REC) == 0 { - if dt := timer.timeElapsed() - t; dt >= ackTimeout { - return false - } - } - - // Set the device address to that requested by host. - rp.USB.ADDR_ENDP.Set(uint32(setup.WValueL) & rp.USB_ADDR_ENDP_ADDRESS_Msk) - return true -} - -func armEPZeroStall() { - rp.USB.EP_STALL_ARM.Set(rp.USB_EP_STALL_ARM_EP0_IN) -} diff --git a/emb/machine/machine_rp2_2040.go b/emb/machine/machine_rp2_2040.go deleted file mode 100644 index 9cdb3a0..0000000 --- a/emb/machine/machine_rp2_2040.go +++ /dev/null @@ -1,223 +0,0 @@ -//go:build rp2040 - -package machine - -import ( - "device/rp" - "runtime/volatile" - "unsafe" -) - -const ( - cpuFreq = 200 * MHz - _NUMBANK0_GPIOS = 30 - _NUMBANK0_IRQS = 4 - _NUMIRQ = 32 - rp2350ExtraReg = 0 - RESETS_RESET_Msk = 0x01ffffff - initUnreset = rp.RESETS_RESET_ADC | - rp.RESETS_RESET_RTC | - rp.RESETS_RESET_SPI0 | - rp.RESETS_RESET_SPI1 | - rp.RESETS_RESET_UART0 | - rp.RESETS_RESET_UART1 | - rp.RESETS_RESET_USBCTRL - initDontReset = rp.RESETS_RESET_IO_QSPI | - rp.RESETS_RESET_PADS_QSPI | - rp.RESETS_RESET_PLL_USB | - rp.RESETS_RESET_USBCTRL | - rp.RESETS_RESET_SYSCFG | - rp.RESETS_RESET_PLL_SYS - padEnableMask = rp.PADS_BANK0_GPIO0_IE_Msk | - rp.PADS_BANK0_GPIO0_OD_Msk -) - -const ( - PinOutput PinMode = iota - PinInput - PinInputPulldown - PinInputPullup - PinAnalog - PinUART - PinPWM - PinI2C - PinSPI - PinPIO0 - PinPIO1 -) - -// Analog pins on RP2040. -const ( - ADC0 Pin = GPIO26 - ADC1 Pin = GPIO27 - ADC2 Pin = GPIO28 - ADC3 Pin = GPIO29 - - thermADC = 30 -) - -const ( - clkGPOUT0 clockIndex = iota // GPIO Muxing 0 - clkGPOUT1 // GPIO Muxing 1 - clkGPOUT2 // GPIO Muxing 2 - clkGPOUT3 // GPIO Muxing 3 - clkRef // Watchdog and timers reference clock - clkSys // Processors, bus fabric, memory, memory mapped registers - clkPeri // Peripheral clock for UART and SPI - clkUSB // USB clock - clkADC // ADC clock - clkRTC // Real time clock - numClocks -) - -func calcClockDiv(srcFreq, freq uint32) uint32 { - // Div register is 24.8 int.frac divider so multiply by 2^8 (left shift by 8) - return uint32((uint64(srcFreq) << 8) / uint64(freq)) -} - -type clocksType struct { - clk [numClocks]clockType - resus struct { - ctrl volatile.Register32 - status volatile.Register32 - } - fc0 fc - wakeEN0 volatile.Register32 - wakeEN1 volatile.Register32 - sleepEN0 volatile.Register32 - sleepEN1 volatile.Register32 - enabled0 volatile.Register32 - enabled1 volatile.Register32 - intR volatile.Register32 - intE volatile.Register32 - intF volatile.Register32 - intS volatile.Register32 -} - -// GPIO function selectors -const ( - fnJTAG pinFunc = 0 - fnSPI pinFunc = 1 // Connect one of the internal PL022 SPI peripherals to GPIO - fnUART pinFunc = 2 - fnI2C pinFunc = 3 - // Connect a PWM slice to GPIO. There are eight PWM slices, - // each with two outputchannels (A/B). The B pin can also be used as an input, - // for frequency and duty cyclemeasurement - fnPWM pinFunc = 4 - // Software control of GPIO, from the single-cycle IO (SIO) block. - // The SIO function (F5)must be selected for the processors to drive a GPIO, - // but the input is always connected,so software can check the state of GPIOs at any time. - fnSIO pinFunc = 5 - // Connect one of the programmable IO blocks (PIO) to GPIO. PIO can implement a widevariety of interfaces, - // and has its own internal pin mapping hardware, allowing flexibleplacement of digital interfaces on bank 0 GPIOs. - // The PIO function (F6, F7) must beselected for PIO to drive a GPIO, but the input is always connected, - // so the PIOs canalways see the state of all pins. - fnPIO0, fnPIO1 pinFunc = 6, 7 - // General purpose clock inputs/outputs. Can be routed to a number of internal clock domains onRP2040, - // e.g. Input: to provide a 1 Hz clock for the RTC, or can be connected to an internalfrequency counter. - // e.g. Output: optional integer divide - fnGPCK pinFunc = 8 - // USB power control signals to/from the internal USB controller - fnUSB pinFunc = 9 - fnNULL pinFunc = 0x1f - - fnXIP pinFunc = 0 -) - -// Configure configures the gpio pin as per mode. -func (p Pin) Configure(config PinConfig) { - if p == NoPin { - return - } - p.init() - mask := uint32(1) << p - switch config.Mode { - case PinOutput: - p.setFunc(fnSIO) - rp.SIO.GPIO_OE_SET.Set(mask) - case PinInput: - p.setFunc(fnSIO) - p.pulloff() - case PinInputPulldown: - p.setFunc(fnSIO) - p.pulldown() - case PinInputPullup: - p.setFunc(fnSIO) - p.pullup() - case PinAnalog: - p.setFunc(fnNULL) - p.pulloff() - case PinUART: - p.setFunc(fnUART) - case PinPWM: - p.setFunc(fnPWM) - case PinI2C: - // IO config according to 4.3.1.3 of rp2040 datasheet. - p.setFunc(fnI2C) - p.pullup() - p.setSchmitt(true) - p.setSlew(false) - case PinSPI: - p.setFunc(fnSPI) - case PinPIO0: - p.setFunc(fnPIO0) - case PinPIO1: - p.setFunc(fnPIO1) - } -} - -var ( - timer = (*timerType)(unsafe.Pointer(rp.TIMER)) -) - -// Enable or disable a specific interrupt on the executing core. -// num is the interrupt number which must be in [0,31]. -func irqSet(num uint32, enabled bool) { - if num >= _NUMIRQ { - return - } - irqSetMask(1<= 32 { - mask := uint32(1) << (p % 32) - rp.SIO.GPIO_HI_OE_SET.Set(mask) - } else { - mask := uint32(1) << p - rp.SIO.GPIO_OE_SET.Set(mask) - } - case PinInput: - p.setFunc(fnSIO) - p.pulloff() - case PinInputPulldown: - p.setFunc(fnSIO) - p.pulldown() - case PinInputPullup: - p.setFunc(fnSIO) - p.pullup() - case PinAnalog: - p.setFunc(fnNULL) - p.pulloff() - case PinUART: - p.setFunc(fnUART) - case PinPWM: - p.setFunc(fnPWM) - case PinI2C: - // IO config according to 4.3.1.3 of rp2040 datasheet. - p.setFunc(fnI2C) - p.pullup() - p.setSchmitt(true) - p.setSlew(false) - case PinSPI: - p.setFunc(fnSPI) - case PinPIO0: - p.setFunc(fnPIO0) - case PinPIO1: - p.setFunc(fnPIO1) - case PinPIO2: - p.setFunc(fnPIO2) - } -} - -var ( - timer = (*timerType)(unsafe.Pointer(rp.TIMER0)) -) - -// Enable or disable a specific interrupt on the executing core. -// num is the interrupt number which must be in [0,_NUMIRQ). -func irqSet(num uint32, enabled bool) { - if num >= _NUMIRQ { - return - } - - register_index := num / 32 - var mask uint32 = 1 << (num % 32) - - if enabled { - // Clear pending before enable - //(if IRQ is actually asserted, it will immediately re-pend) - if register_index == 0 { - rp.PPB.NVIC_ICPR0.Set(mask) - rp.PPB.NVIC_ISER0.Set(mask) - } else { - rp.PPB.NVIC_ICPR1.Set(mask) - rp.PPB.NVIC_ISER1.Set(mask) - } - } else { - if register_index == 0 { - rp.PPB.NVIC_ICER0.Set(mask) - } else { - rp.PPB.NVIC_ICER1.Set(mask) - } - } -} - -func (clks *clocksType) initRTC() {} // No RTC on RP2350. - -func (clks *clocksType) initTicks() { - rp.TICKS.SetTIMER0_CTRL_ENABLE(0) - rp.TICKS.SetTIMER0_CYCLES(12) - rp.TICKS.SetTIMER0_CTRL_ENABLE(1) -} - -// startTick starts the watchdog tick. -// On RP2040, the watchdog contained a tick generator used to generate a 1μs tick for the watchdog. This was also -// distributed to the system timer. On RP2350, the watchdog instead takes a tick input from the system-level ticks block. See Section 8.5. -func (wd *watchdogImpl) startTick(cycles uint32) { - rp.TICKS.WATCHDOG_CTRL.SetBits(1) -} - -func adjustCoreVoltage() bool { - return false -} diff --git a/emb/machine/machine_rp2_2350a.go b/emb/machine/machine_rp2_2350a.go deleted file mode 100644 index 09ec8a1..0000000 --- a/emb/machine/machine_rp2_2350a.go +++ /dev/null @@ -1,14 +0,0 @@ -//go:build rp2350 && !rp2350b - -package machine - -// Analog pins on RP2350a. -const ( - ADC0 Pin = GPIO26 - ADC1 Pin = GPIO27 - ADC2 Pin = GPIO28 - ADC3 Pin = GPIO29 - - // fifth ADC channel. - thermADC = 30 -) diff --git a/emb/machine/machine_rp2_2350b.go b/emb/machine/machine_rp2_2350b.go deleted file mode 100644 index bd5ceeb..0000000 --- a/emb/machine/machine_rp2_2350b.go +++ /dev/null @@ -1,48 +0,0 @@ -//go:build rp2350b - -package machine - -// RP2350B has additional pins. - -const ( - GPIO30 Pin = 30 // peripherals: PWM7 channel A - GPIO31 Pin = 31 // peripherals: PWM7 channel B - GPIO32 Pin = 32 // peripherals: PWM8 channel A - GPIO33 Pin = 33 // peripherals: PWM8 channel B - GPIO34 Pin = 34 // peripherals: PWM9 channel A - GPIO35 Pin = 35 // peripherals: PWM9 channel B - GPIO36 Pin = 36 // peripherals: PWM10 channel A - GPIO37 Pin = 37 // peripherals: PWM10 channel B - GPIO38 Pin = 38 // peripherals: PWM11 channel A - GPIO39 Pin = 39 // peripherals: PWM11 channel B - GPIO40 Pin = 40 // peripherals: PWM8 channel A - GPIO41 Pin = 41 // peripherals: PWM8 channel B - GPIO42 Pin = 42 // peripherals: PWM9 channel A - GPIO43 Pin = 43 // peripherals: PWM9 channel B - GPIO44 Pin = 44 // peripherals: PWM10 channel A - GPIO45 Pin = 45 // peripherals: PWM10 channel B - GPIO46 Pin = 46 // peripherals: PWM11 channel A - GPIO47 Pin = 47 // peripherals: PWM11 channel B -) - -// Analog pins on 2350b. -const ( - ADC0 Pin = GPIO40 - ADC1 Pin = GPIO41 - ADC2 Pin = GPIO42 - ADC3 Pin = GPIO43 - ADC4 Pin = GPIO44 - ADC5 Pin = GPIO45 - ADC6 Pin = GPIO46 - ADC7 Pin = GPIO47 - // Ninth ADC channel. - thermADC = 48 -) - -// Additional PWMs on the RP2350B. -var ( - PWM8 = getPWMGroup(8) - PWM9 = getPWMGroup(9) - PWM10 = getPWMGroup(10) - PWM11 = getPWMGroup(11) -) diff --git a/emb/machine/machine_rp2_adc.go b/emb/machine/machine_rp2_adc.go deleted file mode 100644 index fc9a826..0000000 --- a/emb/machine/machine_rp2_adc.go +++ /dev/null @@ -1,114 +0,0 @@ -//go:build rp2040 || rp2350 - -package machine - -import ( - "device/rp" - "errors" - "sync" -) - -// ADCChannel is the ADC peripheral mux channel. 0-4. -type ADCChannel uint8 - -// Used to serialise ADC sampling -var adcLock sync.Mutex - -// ADC peripheral reference voltage (mV) -var adcAref uint32 - -// InitADC resets the ADC peripheral. -func InitADC() { - rp.RESETS.RESET.SetBits(rp.RESETS_RESET_ADC) - rp.RESETS.RESET.ClearBits(rp.RESETS_RESET_ADC) - for !rp.RESETS.RESET_DONE.HasBits(rp.RESETS_RESET_ADC) { - } - // enable ADC - rp.ADC.CS.Set(rp.ADC_CS_EN) - adcAref = 3300 - waitForReady() -} - -// Configure sets the ADC pin to analog input mode. -func (a ADC) Configure(config ADCConfig) error { - c, err := a.GetADCChannel() - if err != nil { - return err - } - return c.Configure(config) -} - -// Get returns a one-shot ADC sample reading. -func (a ADC) Get() uint16 { - if c, err := a.GetADCChannel(); err == nil { - return c.getOnce() - } - // Not an ADC pin! - return 0 -} - -// GetADCChannel returns the channel associated with the ADC pin. -func (a ADC) GetADCChannel() (c ADCChannel, err error) { - if a.Pin < ADC0 { - return 0, errors.New("no ADC channel for pin value") - } - return ADCChannel(a.Pin - ADC0), nil -} - -// Configure sets the channel's associated pin to analog input mode. -// The powered on temperature sensor increases ADC_AVDD current by approximately 40 μA. -func (c ADCChannel) Configure(config ADCConfig) error { - if config.Reference != 0 { - adcAref = config.Reference - } - p, err := c.Pin() - if err != nil { - return err - } - p.Configure(PinConfig{Mode: PinAnalog}) - return nil -} - -// getOnce returns a one-shot ADC sample reading from an ADC channel. -func (c ADCChannel) getOnce() uint16 { - // Make it safe to sample multiple ADC channels in separate go routines. - adcLock.Lock() - rp.ADC.CS.ReplaceBits(uint32(c), 0b111, rp.ADC_CS_AINSEL_Pos) - rp.ADC.CS.SetBits(rp.ADC_CS_START_ONCE) - - waitForReady() - adcLock.Unlock() - - // rp2040 is a 12-bit ADC, scale raw reading to 16-bits. - return uint16(rp.ADC.RESULT.Get()) << 4 -} - -// getVoltage does a one-shot sample and returns a millivolts reading. -// Integer portion is stored in the high 16 bits and fractional in the low 16 bits. -func (c ADCChannel) getVoltage() uint32 { - return (adcAref << 16) / (1 << 12) * uint32(c.getOnce()>>4) -} - -// ReadTemperature does a one-shot sample of the internal temperature sensor and returns a milli-celsius reading. -func ReadTemperature() (millicelsius int32) { - if rp.ADC.CS.Get()&rp.ADC_CS_EN == 0 { - InitADC() - } - thermChan, _ := ADC{Pin: thermADC}.GetADCChannel() - // Enable temperature sensor bias source - rp.ADC.CS.SetBits(rp.ADC_CS_TS_EN) - - // T = 27 - (ADC_voltage - 0.706)/0.001721 - return (27000<<16 - (int32(thermChan.getVoltage())-706<<16)*581) >> 16 -} - -// waitForReady spins waiting for the ADC peripheral to become ready. -func waitForReady() { - for !rp.ADC.CS.HasBits(rp.ADC_CS_READY) { - } -} - -// The Pin method returns the GPIO Pin associated with the ADC mux channel, if it has one. -func (c ADCChannel) Pin() (p Pin, err error) { - return Pin(c) + ADC0, nil -} diff --git a/emb/machine/machine_rp2_clocks.go b/emb/machine/machine_rp2_clocks.go deleted file mode 100644 index dafebbe..0000000 --- a/emb/machine/machine_rp2_clocks.go +++ /dev/null @@ -1,236 +0,0 @@ -//go:build rp2040 || rp2350 - -package machine - -import ( - "device/arm" - "device/rp" - "runtime/volatile" - "unsafe" -) - -func CPUFrequency() uint32 { - return cpuFreq -} - -// clockIndex identifies a hardware clock -type clockIndex uint8 - -type clockType struct { - ctrl volatile.Register32 - div volatile.Register32 - selected volatile.Register32 -} - -type fc struct { - refKHz volatile.Register32 - minKHz volatile.Register32 - maxKHz volatile.Register32 - delay volatile.Register32 - interval volatile.Register32 - src volatile.Register32 - status volatile.Register32 - result volatile.Register32 -} - -var clocks = (*clocksType)(unsafe.Pointer(rp.CLOCKS)) - -var configuredFreq [numClocks]uint32 - -type clock struct { - *clockType - cix clockIndex -} - -// The delay in seconds for core voltage adjustments to -// settle. Taken from the Pico SDK. -const _VREG_VOLTAGE_AUTO_ADJUST_DELAY = 1 / 1e3 - -// clock returns the clock identified by cix. -func (clks *clocksType) clock(cix clockIndex) clock { - return clock{ - &clks.clk[cix], - cix, - } -} - -// hasGlitchlessMux returns true if clock contains a glitchless multiplexer. -// -// Clock muxing consists of two components: -// -// A glitchless mux, which can be switched freely, but whose inputs must be -// free-running. -// -// An auxiliary (glitchy) mux, whose output glitches when switched, but has -// no constraints on its inputs. -// -// Not all clocks have both types of mux. -func (clk *clock) hasGlitchlessMux() bool { - return clk.cix == clkSys || clk.cix == clkRef -} - -// configure configures the clock by selecting the main clock source src -// and the auxiliary clock source auxsrc -// and finally setting the clock frequency to freq -// given the input clock source frequency srcFreq. -func (clk *clock) configure(src, auxsrc, srcFreq, freq uint32) { - if freq > srcFreq { - panic("clock frequency cannot be greater than source frequency") - } - - div := calcClockDiv(srcFreq, freq) - - // If increasing divisor, set divisor before source. Otherwise set source - // before divisor. This avoids a momentary overspeed when e.g. switching - // to a faster source and increasing divisor to compensate. - if div > clk.div.Get() { - clk.div.Set(div) - } - - // If switching a glitchless slice (ref or sys) to an aux source, switch - // away from aux *first* to avoid passing glitches when changing aux mux. - // Assume (!!!) glitchless source 0 is no faster than the aux source. - if clk.hasGlitchlessMux() && src == rp.CLOCKS_CLK_SYS_CTRL_SRC_CLKSRC_CLK_SYS_AUX { - clk.ctrl.ClearBits(rp.CLOCKS_CLK_REF_CTRL_SRC_Msk) - for !clk.selected.HasBits(1) { - } - } else - // If no glitchless mux, cleanly stop the clock to avoid glitches - // propagating when changing aux mux. Note it would be a really bad idea - // to do this on one of the glitchless clocks (clkSys, clkRef). - { - // Disable clock. On clkRef and ClkSys this does nothing, - // all other clocks have the ENABLE bit in the same position. - clk.ctrl.ClearBits(rp.CLOCKS_CLK_GPOUT0_CTRL_ENABLE_Msk) - if configuredFreq[clk.cix] > 0 { - // Delay for 3 cycles of the target clock, for ENABLE propagation. - // Note XOSC_COUNT is not helpful here because XOSC is not - // necessarily running, nor is timer... so, 3 cycles per loop: - delayCyc := configuredFreq[clkSys]/configuredFreq[clk.cix] + 1 - for delayCyc != 0 { - // This could be done more efficiently but TinyGo inline - // assembly is not yet capable enough to express that. In the - // meantime, this forces at least 3 cycles per loop. - delayCyc-- - arm.Asm("nop\nnop\nnop") - } - } - } - - // Set aux mux first, and then glitchless mux if this clock has one. - clk.ctrl.ReplaceBits(auxsrc< FlashDataEnd() { - return 0, errFlashCannotReadPastEOF - } - - data := unsafe.Slice((*byte)(unsafe.Pointer(readAddress(off))), len(p)) - copy(p, data) - - return len(p), nil -} - -// WriteAt writes the given number of bytes to the block device. -// Only word (32 bits) length data can be programmed. -// If the length of p is not long enough it will be padded with 0xFF bytes. -// This method assumes that the destination is already erased. -func (f flashBlockDevice) WriteAt(p []byte, off int64) (n int, err error) { - return f.writeAt(p, off) -} - -// Size returns the number of bytes in this block device. -func (f flashBlockDevice) Size() int64 { - return int64(FlashDataEnd() - FlashDataStart()) -} - -const writeBlockSize = 1 << 8 - -// WriteBlockSize returns the block size in which data can be written to -// memory. It can be used by a client to optimize writes, non-aligned writes -// should always work correctly. -func (f flashBlockDevice) WriteBlockSize() int64 { - return writeBlockSize -} - -const eraseBlockSizeValue = 1 << 12 - -func eraseBlockSize() int64 { - return eraseBlockSizeValue -} - -// EraseBlockSize returns the smallest erasable area on this particular chip -// in bytes. This is used for the block size in EraseBlocks. -func (f flashBlockDevice) EraseBlockSize() int64 { - return eraseBlockSize() -} - -// EraseBlocks erases the given number of blocks. An implementation may -// transparently coalesce ranges of blocks into larger bundles if the chip -// supports this. The start and len parameters are in block numbers, use -// EraseBlockSize to map addresses to blocks. -func (f flashBlockDevice) EraseBlocks(start, length int64) error { - return f.eraseBlocks(start, length) -} - -// return the correct address to be used for write -func writeAddress(off int64) uintptr { - return readAddress(off) - uintptr(memoryStart) -} - -// return the correct address to be used for reads -func readAddress(off int64) uintptr { - return FlashDataStart() + uintptr(off) -} diff --git a/emb/machine/machine_rp2_gpio.go b/emb/machine/machine_rp2_gpio.go deleted file mode 100644 index 25d7626..0000000 --- a/emb/machine/machine_rp2_gpio.go +++ /dev/null @@ -1,282 +0,0 @@ -//go:build rp2040 || rp2350 - -package machine - -import ( - "device/rp" - "runtime/interrupt" - "runtime/volatile" - "unsafe" -) - -type ioType struct { - status volatile.Register32 - ctrl volatile.Register32 -} - -type irqCtrl struct { - intE [_NUMBANK0_IRQS]volatile.Register32 - intF [_NUMBANK0_IRQS]volatile.Register32 - intS [_NUMBANK0_IRQS]volatile.Register32 -} - -type irqSummary struct { - proc [2]struct { - secure [2]volatile.Register32 - nonsecure [2]volatile.Register32 - } - comaWake struct { - secure [2]volatile.Register32 - nonsecure [2]volatile.Register32 - } -} - -type ioBank0Type struct { - io [_NUMBANK0_GPIOS]ioType - _ [rp2350ExtraReg][128]byte - irqsum [rp2350ExtraReg]irqSummary - intR [_NUMBANK0_IRQS]volatile.Register32 - proc0IRQctrl irqCtrl - proc1IRQctrl irqCtrl - dormantWakeIRQctrl irqCtrl -} - -var ioBank0 = (*ioBank0Type)(unsafe.Pointer(rp.IO_BANK0)) - -type padsBank0Type struct { - voltageSelect volatile.Register32 - io [_NUMBANK0_GPIOS]volatile.Register32 -} - -var padsBank0 = (*padsBank0Type)(unsafe.Pointer(rp.PADS_BANK0)) - -// pinFunc represents a GPIO function. -// -// Each GPIO can have one function selected at a time. -// Likewise, each peripheral input (e.g. UART0 RX) should only be selected -// on one GPIO at a time. If the same peripheral input is connected to multiple GPIOs, -// the peripheral sees the logical OR of these GPIO inputs. -type pinFunc uint8 - -func (p Pin) PortMaskSet() (*uint32, uint32) { - return (*uint32)(unsafe.Pointer(&rp.SIO.GPIO_OUT_SET)), 1 << p -} - -// set drives the pin high -func (p Pin) set() { - if is48Pin && p >= 32 { - mask := uint32(1) << (p % 32) - rp.SIO.GPIO_HI_OUT_SET.Set(mask) - } else { - mask := uint32(1) << p - rp.SIO.GPIO_OUT_SET.Set(mask) - } -} - -func (p Pin) PortMaskClear() (*uint32, uint32) { - return (*uint32)(unsafe.Pointer(&rp.SIO.GPIO_OUT_CLR)), 1 << p -} - -// clr drives the pin low -func (p Pin) clr() { - if is48Pin && p >= 32 { - mask := uint32(1) << (p % 32) - rp.SIO.GPIO_HI_OUT_CLR.Set(mask) - } else { - mask := uint32(1) << p - rp.SIO.GPIO_OUT_CLR.Set(mask) - } -} - -// xor toggles the pin -func (p Pin) xor() { - if is48Pin && p >= 32 { - mask := uint32(1) << (p % 32) - rp.SIO.GPIO_HI_OUT_XOR.Set(mask) - } else { - mask := uint32(1) << p - rp.SIO.GPIO_OUT_XOR.Set(mask) - } -} - -// get returns the pin value -func (p Pin) get() bool { - if is48Pin && p >= 32 { - return rp.SIO.GPIO_HI_IN.HasBits(1 << (p % 32)) - } - return rp.SIO.GPIO_IN.HasBits(1 << p) -} - -func (p Pin) ioCtrl() *volatile.Register32 { - return &ioBank0.io[p].ctrl -} - -func (p Pin) padCtrl() *volatile.Register32 { - return &padsBank0.io[p] -} - -func (p Pin) pullup() { - p.padCtrl().SetBits(rp.PADS_BANK0_GPIO0_PUE) - p.padCtrl().ClearBits(rp.PADS_BANK0_GPIO0_PDE) -} - -func (p Pin) pulldown() { - p.padCtrl().SetBits(rp.PADS_BANK0_GPIO0_PDE) - p.padCtrl().ClearBits(rp.PADS_BANK0_GPIO0_PUE) -} - -func (p Pin) pulloff() { - p.padCtrl().ClearBits(rp.PADS_BANK0_GPIO0_PDE) - p.padCtrl().ClearBits(rp.PADS_BANK0_GPIO0_PUE) -} - -// setSlew sets pad slew rate control. -// true sets to fast. false sets to slow. -func (p Pin) setSlew(sr bool) { - p.padCtrl().ReplaceBits(boolToBit(sr)<= 32 { - mask := uint32(1) << (p % 32) - rp.SIO.GPIO_HI_OE_CLR.Set(mask) - } else { - mask := uint32(1) << p - rp.SIO.GPIO_OE_CLR.Set(mask) - } - p.clr() -} - -// Set drives the pin high if value is true else drives it low. -func (p Pin) Set(value bool) { - if p == NoPin { - return - } - if value { - p.set() - } else { - p.clr() - } -} - -// Get reads the pin value. -func (p Pin) Get() bool { - return p.get() -} - -// PinChange represents one or more trigger events that can happen on a given GPIO pin -// on the RP2040. ORed PinChanges are valid input to most IRQ functions. -type PinChange uint8 - -// Pin change interrupt constants for SetInterrupt. -const ( - // Edge falling - PinFalling PinChange = 4 << iota - // Edge rising - PinRising - - PinToggle = PinFalling | PinRising -) - -// Callbacks to be called for pins configured with SetInterrupt. -var ( - pinCallbacks [2][_NUMBANK0_GPIOS]func(Pin) - setInt [2][_NUMBANK0_GPIOS]bool -) - -// SetInterrupt sets an interrupt to be executed when a particular pin changes -// state. The pin should already be configured as an input, including a pull up -// or down if no external pull is provided. -// -// This call will replace a previously set callback on this pin. You can pass a -// nil func to unset the pin change interrupt. If you do so, the change -// parameter is ignored and can be set to any value (such as 0). -func (p Pin) SetInterrupt(change PinChange, callback func(Pin)) error { - if p == NoPin { - return nil - } - if p > 31 || p < 0 { - return ErrInvalidInputPin - } - core := CurrentCore() - if callback == nil { - // disable current interrupt - p.setInterrupt(change, false) - pinCallbacks[core][p] = nil - return nil - } - - if pinCallbacks[core][p] != nil { - // Callback already configured. Should disable callback by passing a nil callback first. - return ErrNoPinChangeChannel - } - p.setInterrupt(change, true) - pinCallbacks[core][p] = callback - - if setInt[core][p] { - // interrupt has already been set. Exit. - return nil - } - interrupt.New(rp.IRQ_IO_IRQ_BANK0, gpioHandleInterrupt).Enable() - irqSet(rp.IRQ_IO_IRQ_BANK0, true) - return nil -} - -// gpioHandleInterrupt finds the corresponding pin for the interrupt. -// C SDK equivalent of gpio_irq_handler -func gpioHandleInterrupt(intr interrupt.Interrupt) { - - core := CurrentCore() - var gpio Pin - for gpio = 0; gpio < _NUMBANK0_GPIOS; gpio++ { - var base *irqCtrl - switch core { - case 0: - base = &ioBank0.proc0IRQctrl - case 1: - base = &ioBank0.proc1IRQctrl - } - - statreg := base.intS[gpio>>3].Get() - change := getIntChange(gpio, statreg) - if change != 0 { - gpio.acknowledgeInterrupt(change) - callback := pinCallbacks[core][gpio] - if callback != nil { - callback(gpio) - } - } - } -} - -// events returns the bit representation of the pin change for the rp2040. -func (change PinChange) events() uint32 { - return uint32(change) -} - -// intBit is the bit storage form of a PinChange for a given Pin -// in the IO_BANK0 interrupt registers (page 269 RP2040 Datasheet). -func (p Pin) ioIntBit(change PinChange) uint32 { - return change.events() << (4 * (p % 8)) -} - -// Acquire interrupt data from a INT status register. -func getIntChange(p Pin, status uint32) PinChange { - return PinChange(status>>(4*(p%8))) & 0xf -} diff --git a/emb/machine/machine_rp2_i2c.go b/emb/machine/machine_rp2_i2c.go deleted file mode 100644 index 54a5e53..0000000 --- a/emb/machine/machine_rp2_i2c.go +++ /dev/null @@ -1,639 +0,0 @@ -//go:build rp2040 || rp2350 - -package machine - -import ( - "device/rp" - "errors" - "internal/itoa" -) - -// I2C on the RP2040/RP2350 -var ( - I2C0 = &_I2C0 - _I2C0 = I2C{ - Bus: rp.I2C0, - } - I2C1 = &_I2C1 - _I2C1 = I2C{ - Bus: rp.I2C1, - } -) - -// The I2C target implementation is based on the C implementation from -// here: https://github.com/vmilea/pico_i2c_slave - -// Features: Taken from datasheet. -// Default controller mode, with target mode available (not simultaneously). -// Default target address of RP2040: 0x055 -// Supports 10-bit addressing in controller mode -// 16-element transmit buffer -// 16-element receive buffer -// Can be driven from DMA -// Can generate interrupts -// Fast mode plus max transfer speed (1000kb/s) - -// GPIO config -// Each controller must connect its clock SCL and data SDA to one pair of GPIOs. -// The I2C standard requires that drivers drivea signal low, or when not driven the signal will be pulled high. -// This applies to SCL and SDA. The GPIO pads should be configured for: -// Pull-up enabled -// Slew rate limited -// Schmitt trigger enabled -// Note: There should also be external pull-ups on the board as the internal pad pull-ups may not be strong enough to pull upexternal circuits. - -// I2CConfig is used to store config info for I2C. -type I2CConfig struct { - Frequency uint32 - // SDA/SCL Serial Data and clock pins. Refer to datasheet to see - // which pins match the desired bus. - SDA, SCL Pin - Mode I2CMode -} - -type I2C struct { - Bus *rp.I2C0_Type - mode I2CMode - txInProgress bool -} - -var ( - errInvalidI2CBaudrate = errors.New("i2c: invalid baudrate") - errInvalidTgtAddr = errors.New("i2c: invalid target address: not in 0..0x80 or is reserved") - errI2CGeneric = errors.New("i2c: generic error") - errI2CDisable = errors.New("i2c: peripheral timeout in disable") - errInvalidI2CSDA = errors.New("i2c: invalid SDA pin") - errInvalidI2CSCL = errors.New("i2c: invalid SCL pin") - errI2CAlreadyListening = errors.New("i2c: already listening") - errI2CWrongMode = errors.New("i2c: wrong mode") - errI2CUnderflow = errors.New("i2c: underflow") -) - -// Tx performs a write and then a read transfer placing the result in -// in r. -// -// Passing a nil value for w or r skips the transfer corresponding to write -// or read, respectively. -// -// i2c.Tx(addr, nil, r) -// -// Performs only a read transfer. -// -// i2c.Tx(addr, w, nil) -// -// Performs only a write transfer. -func (i2c *I2C) Tx(addr uint16, w, r []byte) error { - if i2c.mode != I2CModeController { - return errI2CWrongMode - } - return i2c.tx(uint8(addr), w, r) -} - -// Listen starts listening for I2C requests sent to specified address -// -// addr is the address to listen to -func (i2c *I2C) Listen(addr uint16) error { - if i2c.mode != I2CModeTarget { - return errI2CWrongMode - } - - return i2c.listen(uint8(addr)) -} - -// Configure initializes i2c peripheral and configures I2C config's pins passed. -// Here's a list of valid SDA and SCL GPIO pins on bus I2C0 of the rp2040: -// -// SDA: 0, 4, 8, 12, 16, 20 -// SCL: 1, 5, 9, 13, 17, 21 -// -// Same as above for I2C1 bus: -// -// SDA: 2, 6, 10, 14, 18, 26 -// SCL: 3, 7, 11, 15, 19, 27 -func (i2c *I2C) Configure(config I2CConfig) error { - const defaultBaud uint32 = 100_000 // 100kHz standard mode - if config.SCL == 0 && config.SDA == 0 { - // If config pins are zero valued or clock pin is invalid then we set default values. - switch i2c.Bus { - case rp.I2C0: - config.SCL = I2C0_SCL_PIN - config.SDA = I2C0_SDA_PIN - case rp.I2C1: - config.SCL = I2C1_SCL_PIN - config.SDA = I2C1_SDA_PIN - } - } - var okSCL, okSDA bool - switch i2c.Bus { - case rp.I2C0: - okSCL = (config.SCL+3)%4 == 0 - okSDA = (config.SDA+4)%4 == 0 - case rp.I2C1: - okSCL = (config.SCL+1)%4 == 0 - okSDA = (config.SDA+2)%4 == 0 - } - - switch { - case !okSCL: - return errInvalidI2CSCL - case !okSDA: - return errInvalidI2CSDA - } - - if config.Frequency == 0 { - config.Frequency = defaultBaud - } - config.SDA.Configure(PinConfig{PinI2C}) - config.SCL.Configure(PinConfig{PinI2C}) - return i2c.init(config) -} - -// SetBaudRate sets the I2C frequency. It has the side effect of also -// enabling the I2C hardware if disabled beforehand. -// -//go:inline -func (i2c *I2C) SetBaudRate(br uint32) error { - - if br == 0 { - return errInvalidI2CBaudrate - } - - // I2C is synchronous design that runs from clk_sys - freqin := CPUFrequency() - - // TODO there are some subtleties to I2C timing which we are completely ignoring here - period := (freqin + br/2) / br - lcnt := period * 3 / 5 // oof this one hurts - hcnt := period - lcnt - // Check for out-of-range divisors: - if hcnt > rp.I2C0_IC_FS_SCL_HCNT_IC_FS_SCL_HCNT_Msk || hcnt < 8 || lcnt > rp.I2C0_IC_FS_SCL_LCNT_IC_FS_SCL_LCNT_Msk || lcnt < 8 { - return errInvalidI2CBaudrate - } - - // Per I2C-bus specification a device in standard or fast mode must - // internally provide a hold time of at least 300ns for the SDA signal to - // bridge the undefined region of the falling edge of SCL. A smaller hold - // time of 120ns is used for fast mode plus. - - // sda_tx_hold_count = freq_in [cycles/s] * 300ns * (1s / 1e9ns) - // Reduce 300/1e9 to 3/1e7 to avoid numbers that don't fit in uint. - // Add 1 to avoid division truncation. - sdaTxHoldCnt := ((freqin * 3) / 10000000) + 1 - if br >= 1_000_000 { - // sda_tx_hold_count = freq_in [cycles/s] * 120ns * (1s / 1e9ns) - // Reduce 120/1e9 to 3/25e6 to avoid numbers that don't fit in uint. - // Add 1 to avoid division truncation. - sdaTxHoldCnt = ((freqin * 3) / 25000000) + 1 - } - - if sdaTxHoldCnt > lcnt-2 { - return errInvalidI2CBaudrate - } - err := i2c.disable() - if err != nil { - return err - } - // Always use "fast" mode (<= 400 kHz, works fine for standard mode too) - - i2c.Bus.IC_CON.ReplaceBits(rp.I2C0_IC_CON_SPEED_FAST< deadline { - return errI2CDisable - } - } - return nil -} - -//go:inline -func (i2c *I2C) init(config I2CConfig) error { - i2c.reset() - if err := i2c.disable(); err != nil { - return err - } - - i2c.mode = config.Mode - - // Configure as fast-mode with RepStart support, 7-bit addresses - mode := uint32(rp.I2C0_IC_CON_SPEED_FAST<= 0x80 || isReservedI2CAddr(addr) { - return errInvalidTgtAddr - } - txlen := len(tx) - rxlen := len(rx) - // Quick return if possible. - if txlen == 0 && rxlen == 0 { - return nil - } - - err = i2c.disable() - if err != nil { - return err - } - i2c.Bus.IC_TAR.Set(uint32(addr)) - i2c.enable() - abort := false - var abortReason i2cAbortError - txStop := rxlen == 0 - for txCtr := 0; txCtr < txlen; txCtr++ { - if abort { - break - } - first := txCtr == 0 - last := txCtr == txlen-1 && rxlen == 0 - i2c.Bus.IC_DATA_CMD.Set( - (boolToBit(first) << rp.I2C0_IC_DATA_CMD_RESTART_Pos) | - (boolToBit(last && txStop) << rp.I2C0_IC_DATA_CMD_STOP_Pos) | - uint32(tx[txCtr])) - - // Wait until the transmission of the address/data from the internal - // shift register has completed. For this to function correctly, the - // TX_EMPTY_CTRL flag in IC_CON must be set. The TX_EMPTY_CTRL flag - // was set in i2c_init. - - // IC_RAW_INTR_STAT_TX_EMPTY: This bit is set to 1 when the transmit buffer is at or below - // the threshold value set in the IC_TX_TL register and the - // transmission of the address/data from the internal shift - // register for the most recently popped command is - // completed. It is automatically cleared by hardware when - // the buffer level goes above the threshold. When - // IC_ENABLE[0] is set to 0, the TX FIFO is flushed and held - // in reset. There the TX FIFO looks like it has no data within - // it, so this bit is set to 1, provided there is activity in the - // controller or target state machines. When there is no longer - // any activity, then with ic_en=0, this bit is set to 0. - for !i2c.interrupted(rp.I2C0_IC_RAW_INTR_STAT_TX_EMPTY) { - if ticks() > deadline { - return errI2CWriteTimeout // If there was a timeout, don't attempt to do anything else. - } - - before := ticks() - gosched() - deadline += ticks() - before - } - - abortReason = i2c.getAbortReason() - if abortReason != 0 { - i2c.clearAbortReason() - abort = true - } - if abort || last { - // If the transaction was aborted or if it completed - // successfully wait until the STOP condition has occurred. - - // TODO Could there be an abort while waiting for the STOP - // condition here? If so, additional code would be needed here - // to take care of the abort. - for !i2c.interrupted(rp.I2C0_IC_RAW_INTR_STAT_STOP_DET) { - if ticks() > deadline { - if abort { - return abortReason - } - return errI2CWriteTimeout - } - - before := ticks() - gosched() - deadline += ticks() - before - } - i2c.Bus.IC_CLR_STOP_DET.Get() - } - } - - // Midway check for abort. Related issue https://github.com/tinygo-org/tinygo/issues/3671. - // The root cause for an abort after writing registers was "tx data no ack" (abort code=8). - // If the abort code was not registered then the whole peripheral would remain in disabled state forever. - abortReason = i2c.getAbortReason() - if abortReason != 0 { - i2c.clearAbortReason() - abort = true - } - - rxStart := txlen == 0 - if rxlen > 0 && !abort { - for rxCtr := 0; rxCtr < rxlen; rxCtr++ { - first := rxCtr == 0 - last := rxCtr == rxlen-1 - for i2c.writeAvailable() == 0 { - before := ticks() - gosched() - deadline += ticks() - before - } - i2c.Bus.IC_DATA_CMD.Set( - boolToBit(first && rxStart)< 1 for read - - for !abort && i2c.readAvailable() == 0 { - abortReason = i2c.getAbortReason() - if abortReason != 0 { - i2c.clearAbortReason() - abort = true - } - if ticks() > deadline { - return errI2CReadTimeout // If there was a timeout, don't attempt to do anything else. - } - - before := ticks() - gosched() - deadline += ticks() - before - } - if abort { - break - } - rx[rxCtr] = uint8(i2c.Bus.IC_DATA_CMD.Get()) - } - } - // From Pico SDK: A lot of things could have just happened due to the ingenious and - // creative design of I2C. Try to figure things out. - if abort { - switch { - case abortReason == 0 || abortReason&rp.I2C0_IC_TX_ABRT_SOURCE_ABRT_7B_ADDR_NOACK != 0: - // No reported errors - seems to happen if there is nothing connected to the bus. - // Address byte not acknowledged - err = errI2CGeneric - case abortReason&rp.I2C0_IC_TX_ABRT_SOURCE_ABRT_TXDATA_NOACK != 0: - // Address acknowledged, some data not acknowledged - fallthrough - default: - err = abortReason - } - } - return err -} - -// listen sets up for async handling of requests on the I2C bus. -func (i2c *I2C) listen(addr uint8) error { - if addr >= 0x80 || isReservedI2CAddr(addr) { - return errInvalidTgtAddr - } - - err := i2c.disable() - if err != nil { - return err - } - - i2c.Bus.IC_SAR.Set(uint32(addr)) - - i2c.enable() - - return nil -} - -func (i2c *I2C) WaitForEvent(buf []byte) (evt I2CTargetEvent, count int, err error) { - rxPtr := 0 - for { - stat := i2c.Bus.IC_RAW_INTR_STAT.Get() - - if stat&rp.I2C0_IC_INTR_MASK_M_RX_FULL != 0 { - b := uint8(i2c.Bus.IC_DATA_CMD.Get()) - if rxPtr < len(buf) { - buf[rxPtr] = b - rxPtr++ - } - } - - // Stop - if stat&rp.I2C0_IC_INTR_MASK_M_STOP_DET != 0 { - if rxPtr > 0 { - return I2CReceive, rxPtr, nil - } - - i2c.Bus.IC_CLR_STOP_DET.Get() // clear - return I2CFinish, 0, nil - } - - // Start or restart - ignore start, return on restart - if stat&rp.I2C0_IC_INTR_MASK_M_START_DET != 0 { - i2c.Bus.IC_CLR_START_DET.Get() // clear restart - - // Restart - if rxPtr > 0 { - return I2CReceive, rxPtr, nil - } - } - - // Read request - leave flag set until we start to reply. - if stat&rp.I2C0_IC_INTR_MASK_M_RD_REQ != 0 { - return I2CRequest, 0, nil - } - - gosched() - } -} - -func (i2c *I2C) Reply(buf []byte) error { - txPtr := 0 - - stat := i2c.Bus.IC_RAW_INTR_STAT.Get() - - if stat&rp.I2C0_IC_INTR_MASK_M_RD_REQ == 0 { - return errI2CWrongMode - } - i2c.Bus.IC_CLR_RD_REQ.Get() // clear restart - - // Clear any dangling TX abort - if stat&rp.I2C0_IC_INTR_MASK_M_TX_ABRT != 0 { - i2c.Bus.IC_CLR_TX_ABRT.Get() - } - - for txPtr < len(buf) { - if i2c.Bus.GetIC_RAW_INTR_STAT_TX_EMPTY() != 0 { - i2c.Bus.SetIC_DATA_CMD_DAT(uint32(buf[txPtr])) - txPtr++ - // The DW_apb_i2c flushes/resets/empties the - // TX_FIFO and RX_FIFO whenever there is a transmit abort - // caused by any of the events tracked by the - // IC_TX_ABRT_SOURCE register. - // In other words, it's safe to block until TX FIFO is - // EMPTY--it will empty from being transmitted or on error. - for i2c.Bus.GetIC_RAW_INTR_STAT_TX_EMPTY() == 0 { - } - } - - // This Tx abort is a normal case - we're sending more - // data than controller wants to receive - if i2c.Bus.GetIC_RAW_INTR_STAT_TX_ABRT() != 0 { - i2c.Bus.GetIC_CLR_TX_ABRT_CLR_TX_ABRT() - return nil - } - - gosched() - } - - return nil -} - -// writeAvailable determines non-blocking write space available -// -//go:inline -func (i2c *I2C) writeAvailable() uint32 { - return rp.I2C0_IC_COMP_PARAM_1_TX_BUFFER_DEPTH_Pos - i2c.Bus.IC_TXFLR.Get() -} - -// readAvailable determines number of bytes received -// -//go:inline -func (i2c *I2C) readAvailable() uint32 { - return i2c.Bus.IC_RXFLR.Get() -} - -// Equivalent to IC_CLR_TX_ABRT.Get() (side effect clears ABORT_REASON) -// -//go:inline -func (i2c *I2C) clearAbortReason() { - // Note clearing the abort flag also clears the reason, and - // this instance of flag is clear-on-read! Note also the - // IC_CLR_TX_ABRT register always reads as 0. - i2c.Bus.IC_CLR_TX_ABRT.Get() -} - -// getAbortReason reads IC_TX_ABRT_SOURCE register. -// -//go:inline -func (i2c *I2C) getAbortReason() i2cAbortError { - return i2cAbortError(i2c.Bus.IC_TX_ABRT_SOURCE.Get()) -} - -// returns true if RAW_INTR_STAT bits in mask are all set. performs: -// -// RAW_INTR_STAT & mask == mask -// -//go:inline -func (i2c *I2C) interrupted(mask uint32) bool { - reg := i2c.Bus.IC_RAW_INTR_STAT.Get() - return reg&mask == mask -} - -type i2cAbortError uint32 - -func (b i2cAbortError) Error() string { - return "i2c abort, reason " + itoa.Uitoa(uint(b)) -} - -func (b i2cAbortError) Reasons() (reasons []string) { - if b == 0 { - return nil - } - if b&rp.I2C0_IC_TX_ABRT_SOURCE_ABRT_7B_ADDR_NOACK != 0 { - reasons = append(reasons, "7-bit address no ack") - } - if b&rp.I2C0_IC_TX_ABRT_SOURCE_ABRT_10ADDR1_NOACK != 0 { - reasons = append(reasons, "10-bit address first byte no ack") - } - if b&rp.I2C0_IC_TX_ABRT_SOURCE_ABRT_10ADDR2_NOACK != 0 { - reasons = append(reasons, "10-bit address second byte no ack") - } - if b&rp.I2C0_IC_TX_ABRT_SOURCE_ABRT_TXDATA_NOACK != 0 { - reasons = append(reasons, "tx data no ack") - } - if b&rp.I2C0_IC_TX_ABRT_SOURCE_ABRT_GCALL_NOACK != 0 { - reasons = append(reasons, "general call no ack") - } - if b&rp.I2C0_IC_TX_ABRT_SOURCE_ABRT_GCALL_READ != 0 { - reasons = append(reasons, "general call read") - } - if b&rp.I2C0_IC_TX_ABRT_SOURCE_ABRT_HS_ACKDET != 0 { - reasons = append(reasons, "high speed ack detect") - } - if b&rp.I2C0_IC_TX_ABRT_SOURCE_ABRT_SBYTE_ACKDET != 0 { - reasons = append(reasons, "start byte ack detect") - } - if b&rp.I2C0_IC_TX_ABRT_SOURCE_ABRT_HS_NORSTRT != 0 { - reasons = append(reasons, "high speed no restart") - } - if b&rp.I2C0_IC_TX_ABRT_SOURCE_ABRT_SBYTE_NORSTRT != 0 { - reasons = append(reasons, "start byte no restart") - } - if b&rp.I2C0_IC_TX_ABRT_SOURCE_ABRT_10B_RD_NORSTRT != 0 { - reasons = append(reasons, "10-bit read no restart") - } - if b&rp.I2C0_IC_TX_ABRT_SOURCE_ABRT_MASTER_DIS != 0 { - reasons = append(reasons, "master disabled") - } - if b&rp.I2C0_IC_TX_ABRT_SOURCE_ARB_LOST != 0 { - reasons = append(reasons, "arbitration lost") - } - if b&rp.I2C0_IC_TX_ABRT_SOURCE_ABRT_SLVFLUSH_TXFIFO != 0 { - reasons = append(reasons, "slave flush tx fifo") - } - if b&rp.I2C0_IC_TX_ABRT_SOURCE_ABRT_SLV_ARBLOST != 0 { - reasons = append(reasons, "slave arbitration lost") - } - if b&rp.I2C0_IC_TX_ABRT_SOURCE_ABRT_SLVRD_INTX != 0 { - reasons = append(reasons, "slave read while inactive") - } - if b&rp.I2C0_IC_TX_ABRT_SOURCE_ABRT_USER_ABRT != 0 { - reasons = append(reasons, "user abort") - } - return reasons -} diff --git a/emb/machine/machine_rp2_pins.go b/emb/machine/machine_rp2_pins.go deleted file mode 100644 index 36e9bd6..0000000 --- a/emb/machine/machine_rp2_pins.go +++ /dev/null @@ -1,37 +0,0 @@ -//go:build rp2040 || rp2350 || gopher_badge || pico - -package machine - -const ( - // GPIO pins - GPIO0 Pin = 0 // peripherals: PWM0 channel A - GPIO1 Pin = 1 // peripherals: PWM0 channel B - GPIO2 Pin = 2 // peripherals: PWM1 channel A - GPIO3 Pin = 3 // peripherals: PWM1 channel B - GPIO4 Pin = 4 // peripherals: PWM2 channel A - GPIO5 Pin = 5 // peripherals: PWM2 channel B - GPIO6 Pin = 6 // peripherals: PWM3 channel A - GPIO7 Pin = 7 // peripherals: PWM3 channel B - GPIO8 Pin = 8 // peripherals: PWM4 channel A - GPIO9 Pin = 9 // peripherals: PWM4 channel B - GPIO10 Pin = 10 // peripherals: PWM5 channel A - GPIO11 Pin = 11 // peripherals: PWM5 channel B - GPIO12 Pin = 12 // peripherals: PWM6 channel A - GPIO13 Pin = 13 // peripherals: PWM6 channel B - GPIO14 Pin = 14 // peripherals: PWM7 channel A - GPIO15 Pin = 15 // peripherals: PWM7 channel B - GPIO16 Pin = 16 // peripherals: PWM0 channel A - GPIO17 Pin = 17 // peripherals: PWM0 channel B - GPIO18 Pin = 18 // peripherals: PWM1 channel A - GPIO19 Pin = 19 // peripherals: PWM1 channel B - GPIO20 Pin = 20 // peripherals: PWM2 channel A - GPIO21 Pin = 21 // peripherals: PWM2 channel B - GPIO22 Pin = 22 // peripherals: PWM3 channel A - GPIO23 Pin = 23 // peripherals: PWM3 channel B - GPIO24 Pin = 24 // peripherals: PWM4 channel A - GPIO25 Pin = 25 // peripherals: PWM4 channel B - GPIO26 Pin = 26 // peripherals: PWM5 channel A - GPIO27 Pin = 27 // peripherals: PWM5 channel B - GPIO28 Pin = 28 // peripherals: PWM6 channel A - GPIO29 Pin = 29 // peripherals: PWM6 channel B -) diff --git a/emb/machine/machine_rp2_pll.go b/emb/machine/machine_rp2_pll.go deleted file mode 100644 index d576084..0000000 --- a/emb/machine/machine_rp2_pll.go +++ /dev/null @@ -1,279 +0,0 @@ -//go:build rp2040 || rp2350 - -package machine - -import ( - "device/rp" - "errors" - "math" - "math/bits" - "runtime/volatile" - "unsafe" -) - -type pll struct { - cs volatile.Register32 - pwr volatile.Register32 - fbDivInt volatile.Register32 - prim volatile.Register32 -} - -var ( - pllSys = (*pll)(unsafe.Pointer(rp.PLL_SYS)) - pllUSB = (*pll)(unsafe.Pointer(rp.PLL_USB)) -) - -// init initializes pll (Sys or USB) given the following parameters. -// -// Input clock divider, refdiv. -// -// Requested output frequency from the VCO (voltage controlled oscillator), vcoFreq. -// -// Post Divider 1, postDiv1 with range 1-7 and be >= postDiv2. -// -// Post Divider 2, postDiv2 with range 1-7. -func (pll *pll) init(refdiv, fbdiv, postDiv1, postDiv2 uint32) { - refFreq := xoscFreq / refdiv - - // What are we multiplying the reference clock by to get the vco freq - // (The regs are called div, because you divide the vco output and compare it to the refclk) - - // Check fbdiv range - if !(fbdiv >= 16 && fbdiv <= 320) { - panic("fbdiv should be in the range [16,320]") - } - - // Check divider ranges - if !((postDiv1 >= 1 && postDiv1 <= 7) && (postDiv2 >= 1 && postDiv2 <= 7)) { - panic("postdiv1, postdiv1 should be in the range [1,7]") - } - - // postDiv1 should be >= postDiv2 - // from appnote page 11 - // postdiv1 is designed to operate with a higher input frequency - // than postdiv2 - if postDiv1 < postDiv2 { - panic("postdiv1 should be greater than or equal to postdiv2") - } - - // Check that reference frequency is no greater than vcoFreq / 16 - vcoFreq := calcVCO(xoscFreq, fbdiv, refdiv) - if refFreq > vcoFreq/16 { - panic("reference frequency should not be greater than vco frequency divided by 16") - } - - // div1 feeds into div2 so if div1 is 5 and div2 is 2 then you get a divide by 10 - pdiv := uint32(postDiv1)< maxVCO { - break - } - calcPD12 := vco / targetFreq - if calcPD12 < 1 { - calcPD12 = 1 - } else if calcPD12 > 49 { - calcPD12 = 49 - } - iters++ - pd1 = pdTable[calcPD12].hivco[0] - pd2 = pdTable[calcPD12].hivco[1] - fout, err := pllFreqOutPostdiv(xoscRef, fbdiv, MHz, refdiv, pd1, pd2) - found := false - margin := abs(int64(fout) - int64(targetFreq)) - if err == nil && margin <= bestMargin { - found = true - bestFreq = fout - bestFbdiv = fbdiv - bestpd1 = pd1 - bestpd2 = pd2 - bestRefdiv = refdiv - bestMargin = margin - } - pd1 = pdTable[calcPD12].lovco[0] - pd2 = pdTable[calcPD12].lovco[1] - fout, err = pllFreqOutPostdiv(xoscRef, fbdiv, MHz, refdiv, pd1, pd2) - margin = abs(int64(fout) - int64(targetFreq)) - if err == nil && margin <= bestMargin { - found = true - bestFreq = fout - bestFbdiv = fbdiv - bestpd1 = pd1 - bestpd2 = pd2 - bestRefdiv = refdiv - bestMargin = margin - } - if found && ps.LowerVCO { - break - } - } - } - if bestFreq == 0 { - return fbdiv, refdiv, pd1, pd2, errors.New("no best frequency found") - } - return bestFbdiv, bestRefdiv, bestpd1, bestpd2, nil -} - -func abs(a int64) int64 { - if a == math.MinInt64 { - return math.MaxInt64 - } else if a < 0 { - return -a - } - return a -} - -func pllFreqOutPostdiv(xosc, fbdiv, MHz uint64, refdiv, postdiv1, postdiv2 uint8) (foutpostdiv uint64, err error) { - // testing grounds. - const ( - mhz = 1 - cfref = 12 * mhz // given by crystal oscillator selection. - crefd = 1 - cfbdiv = 100 - cvco = cfref * cfbdiv / crefd - cpd1 = 6 - cpd2 = 2 - foutpd = (cfref / crefd) * cfbdiv / (cpd1 * cpd2) - ) - refFreq := xosc / uint64(refdiv) - overflow, vco := bits.Mul64(xosc, fbdiv) - vco /= uint64(refdiv) - foutpostdiv = vco / uint64(postdiv1*postdiv2) - switch { - case refdiv < 1 || refdiv > 63: - err = errors.New("reference divider out of range") - case fbdiv < 16 || fbdiv > 320: - err = errors.New("feedback divider out of range") - case postdiv1 < 1 || postdiv1 > 7: - err = errors.New("postdiv1 out of range") - case postdiv2 < 1 || postdiv2 > 7: - err = errors.New("postdiv2 out of range") - case postdiv1 < postdiv2: - err = errors.New("user error: use higher value for postdiv1 for lower power consumption") - case vco < 750*MHz || vco > 1600*MHz: - err = errors.New("VCO out of range") - case refFreq < 5*MHz: - err = errors.New("minimum reference frequency breach") - case refFreq > vco/16: - err = errors.New("maximum reference frequency breach") - case vco > 1200*MHz && vco < 1600*MHz && xosc < 75*MHz && refdiv != 1: - err = errors.New("refdiv should be 1 for given VCO and reference frequency") - case overflow != 0: - err = errVCOOverflow - } - if err != nil { - return 0, err - } - return foutpostdiv, nil -} - -func calcVCO(xoscFreq, fbdiv, refdiv uint32) uint32 { - const maxXoscMHz = math.MaxUint32 / 320 / MHz // 13MHz maximum xosc apparently. - if fbdiv > 320 || xoscFreq > math.MaxUint32/320 { - panic("invalid VCO calculation args") - } - return xoscFreq * fbdiv / refdiv -} - -var pdTable = [50]struct { - hivco [2]uint8 - lovco [2]uint8 -}{} - -func genTable() { - if pdTable[1].hivco[1] != 0 { - return // Already generated. - } - for product := 1; product < len(pdTable); product++ { - bestProdhi := 255 - bestProdlo := 255 - for pd1 := 7; pd1 > 0; pd1-- { - for pd2 := pd1; pd2 > 0; pd2-- { - gotprod := pd1 * pd2 - if abs(int64(gotprod-product)) < abs(int64(bestProdlo-product)) { - bestProdlo = gotprod - pdTable[product].lovco[0] = uint8(pd1) - pdTable[product].lovco[1] = uint8(pd2) - } - } - } - for pd1 := 1; pd1 < 8; pd1++ { - for pd2 := 1; pd2 <= pd1; pd2++ { - gotprod := pd1 * pd2 - if abs(int64(gotprod-product)) < abs(int64(bestProdhi-product)) { - bestProdhi = gotprod - pdTable[product].hivco[0] = uint8(pd1) - pdTable[product].hivco[1] = uint8(pd2) - } - } - } - } -} diff --git a/emb/machine/machine_rp2_pwm.go b/emb/machine/machine_rp2_pwm.go deleted file mode 100644 index 772811e..0000000 --- a/emb/machine/machine_rp2_pwm.go +++ /dev/null @@ -1,420 +0,0 @@ -//go:build rp2040 || rp2350 - -package machine - -import ( - "device/rp" - "errors" - "math" - "runtime/volatile" - "unsafe" -) - -var ( - ErrBadPeriod = errors.New("period outside valid range 8ns..268ms") -) - -const ( - maxPWMPins = _NUMBANK0_GPIOS - 1 -) - -// pwmGroup is one PWM peripheral, which consists of a counter and two output -// channels. You can set the frequency using SetPeriod, -// but only for all the channels in this PWM peripheral at once. -// -// div: integer value to reduce counting rate by. Must be greater than or equal to 1. -// -// cc: counter compare level. Contains 2 channel levels. The 16 LSBs are Channel A's level (Duty Cycle) -// and the 16 MSBs are Channel B's level. -// -// top: Wrap. Highest number counter will reach before wrapping over. usually 0xffff. -// -// csr: Clock mode. PWM_CH0_CSR_DIVMODE_xxx registers have 4 possible modes, of which Free-running is used. -// csr contains output polarity bit at PWM_CH0_CSR_x_INV where x is the channel. -// csr contains phase correction bit at PWM_CH0_CSR_PH_CORRECT_Msk. -// csr contains PWM enable bit at PWM_CH0_CSR_EN. If not enabled PWM will not be active. -// -// ctr: PWM counter value. -type pwmGroup struct { - CSR volatile.Register32 - DIV volatile.Register32 - CTR volatile.Register32 - CC volatile.Register32 - TOP volatile.Register32 -} - -// Equivalent of -// -// var pwmSlice []pwmGroup = (*[8]pwmGroup)(unsafe.Pointer(rp.PWM))[:] -// return &pwmSlice[index] -// -// 0x14 is the size of a pwmGroup. -func getPWMGroup(index uintptr) *pwmGroup { - return (*pwmGroup)(unsafe.Add(unsafe.Pointer(rp.PWM), 0x14*index)) -} - -// Hardware Pulse Width Modulation (PWM) API -// PWM peripherals available on RP2040. Each peripheral has 2 pins available for -// a total of 16 available PWM outputs. Some pins may not be available on some boards. -// -// The RP2040 PWM block has 8 identical slices. Each slice can drive two PWM output signals, or -// measure the frequency or duty cycle of an input signal. This gives a total of up to 16 controllable -// PWM outputs. All 30 GPIOs can be driven by the PWM block -// -// The PWM hardware functions by continuously comparing the input value to a free-running counter. This produces a -// toggling output where the amount of time spent at the high output level is proportional to the input value. The fraction of -// time spent at the high signal level is known as the duty cycle of the signal. -// -// The default behaviour of a PWM slice is to count upward until the wrap value (\ref pwm_config_set_wrap) is reached, and then -// immediately wrap to 0. PWM slices also offer a phase-correct mode, where the counter starts to count downward after -// reaching TOP, until it reaches 0 again. -var ( - PWM0 = getPWMGroup(0) - PWM1 = getPWMGroup(1) - PWM2 = getPWMGroup(2) - PWM3 = getPWMGroup(3) - PWM4 = getPWMGroup(4) - PWM5 = getPWMGroup(5) - PWM6 = getPWMGroup(6) - PWM7 = getPWMGroup(7) -) - -// Configure enables and configures this PWM. -func (pwm *pwmGroup) Configure(config PWMConfig) error { - return pwm.init(config, true) -} - -// Channel returns a PWM channel for the given pin. If pin does -// not belong to PWM peripheral ErrInvalidOutputPin error is returned. -// It also configures pin as PWM output. -func (pwm *pwmGroup) Channel(pin Pin) (channel uint8, err error) { - if pin > maxPWMPins || pwmGPIOToSlice(pin) != pwm.peripheral() { - return 3, ErrInvalidOutputPin - } - pin.Configure(PinConfig{PinPWM}) - return pwmGPIOToChannel(pin), nil -} - -// Peripheral returns the RP2040 PWM peripheral which ranges from 0 to 7. Each -// PWM peripheral has 2 channels, A and B which correspond to 0 and 1 in the program. -// This number corresponds to the package's PWM0 throughout PWM7 handles -func PWMPeripheral(pin Pin) (sliceNum uint8, err error) { - if pin > maxPWMPins { - return 0, ErrInvalidOutputPin - } - return pwmGPIOToSlice(pin), nil -} - -// returns the number of the pwm peripheral (0-7) -func (pwm *pwmGroup) peripheral() uint8 { - return uint8((uintptr(unsafe.Pointer(pwm)) - uintptr(unsafe.Pointer(rp.PWM))) / 0x14) -} - -// SetPeriod updates the period of this PWM peripheral in nanoseconds. -// To set a particular frequency, use the following formula: -// -// period = 1e9 / frequency -// -// Where frequency is in hertz. If you use a period of 0, a period -// that works well for LEDs will be picked. -// -// SetPeriod will try not to modify TOP if possible to reach the target period. -// If the period is unattainable with current TOP SetPeriod will modify TOP -// by the bare minimum to reach the target period. It will also enable phase -// correct to reach periods above 130ms. -func (p *pwmGroup) SetPeriod(period uint64) error { - if period == 0 { - period = 1e5 - } - return p.setPeriod(period) -} - -// Top returns the current counter top, for use in duty cycle calculation. -// -// The value returned here is hardware dependent. In general, it's best to treat -// it as an opaque value that can be divided by some number and passed to Set -// (see Set documentation for more information). -func (p *pwmGroup) Top() uint32 { - return p.getWrap() -} - -// Counter returns the current counter value of the timer in this PWM -// peripheral. It may be useful for debugging. -func (p *pwmGroup) Counter() uint32 { - return (p.CTR.Get() & rp.PWM_CH0_CTR_CH0_CTR_Msk) >> rp.PWM_CH0_CTR_CH0_CTR_Pos -} - -// Period returns the used PWM period in nanoseconds. -func (p *pwmGroup) Period() uint64 { - // Lines below can overflow if operations done without care. - // maxInt=255, maxFrac=15, maxTop=65536, maxPHC=1 => maxProduct= (16*255+15) * (65536*2*1e9) = 5.3673e17 < MaxUint64=1.8e19 (close call.) - const compileTimeCheckPeriod uint64 = (255*16 + 15) * (65535 + 1) * 2 * 1e9 - freq := uint64(CPUFrequency()) - top := p.getWrap() - phc := p.getPhaseCorrect() - Int, frac := p.getClockDiv() - return (16*uint64(Int) + uint64(frac)) * uint64((top+1)*(phc+1)*1e9) / (16 * freq) // cycles = (TOP+1) * (CSRPHCorrect + 1) * (DIV_INT + DIV_FRAC/16) -} - -// SetInverting sets whether to invert the output of this channel. -// Without inverting, a 25% duty cycle would mean the output is high for 25% of -// the time and low for the rest. Inverting flips the output as if a NOT gate -// was placed at the output, meaning that the output would be 25% low and 75% -// high with a duty cycle of 25%. -func (p *pwmGroup) SetInverting(channel uint8, inverting bool) { - channel &= 1 - p.setInverting(channel, inverting) -} - -// Set updates the channel value. This is used to control the channel duty -// cycle, in other words the fraction of time the channel output is high (or low -// when inverted). For example, to set it to a 25% duty cycle, use: -// -// pwm.Set(channel, pwm.Top() / 4) -// -// pwm.Set(channel, 0) will set the output to low and pwm.Set(channel, -// pwm.Top()) will set the output to high, assuming the output isn't inverted. -func (p *pwmGroup) Set(channel uint8, value uint32) { - val := uint16(value) - channel &= 1 - p.setChanLevel(channel, val) -} - -// Get current level (last set by Set). Default value on initialization is 0. -func (p *pwmGroup) Get(channel uint8) (value uint32) { - channel &= 1 - return uint32(p.getChanLevel(channel)) -} - -// SetTop sets TOP control register. Max value is 16bit (0xffff). -func (p *pwmGroup) SetTop(top uint32) { - p.setWrap(uint16(top)) -} - -// SetCounter sets counter control register. Max value is 16bit (0xffff). -// Useful for synchronising two different PWM peripherals. -func (p *pwmGroup) SetCounter(ctr uint32) { - p.CTR.Set(ctr) -} - -// Enable enables or disables PWM peripheral channels. -func (p *pwmGroup) Enable(enable bool) { - p.enable(enable) -} - -// IsEnabled returns true if peripheral is enabled. -func (p *pwmGroup) IsEnabled() (enabled bool) { - return (p.CSR.Get()&rp.PWM_CH0_CSR_EN_Msk)>>rp.PWM_CH0_CSR_EN_Pos != 0 -} - -// Initialise a PWM with settings from a configuration object. -// If start is true then PWM starts on initialization. -func (pwm *pwmGroup) init(config PWMConfig, start bool) error { - // Not enable Phase correction - pwm.setPhaseCorrect(false) - - // Clock mode set by default to Free running - pwm.setDivMode(rp.PWM_CH0_CSR_DIVMODE_DIV) - - // Set Output polarity (false/false) - pwm.setInverting(0, false) - pwm.setInverting(1, false) - - // Set wrap. The highest value the counter will reach before returning to zero, also known as TOP. - pwm.setWrap(0xffff) - // period is set after TOP (Wrap). - err := pwm.SetPeriod(config.Period) - if err != nil { - return err - } - // period already set beforea - // Reset counter and compare (pwm level set to zero) - pwm.CTR.ReplaceBits(0, rp.PWM_CH0_CTR_CH0_CTR_Msk, 0) // PWM_CH0_CTR_RESET - pwm.CC.Set(0) // PWM_CH0_CC_RESET - - pwm.enable(start) - return nil -} - -func (pwm *pwmGroup) setPhaseCorrect(correct bool) { - pwm.CSR.ReplaceBits(boolToBit(correct)< maxPeriod || period < 8 { - return ErrBadPeriod - } - if period > maxPeriod/2 { - pwm.setPhaseCorrect(true) // Must enable Phase correct to reach large periods. - } - - // clearing above expression: - // DIV_INT + DIV_FRAC/16 = cycles / ( (TOP+1) * (CSRPHCorrect+1) ) // DIV_FRAC/16 is always 0 in this equation - // where cycles must be converted to time: - // target_period = cycles * period_per_cycle ==> cycles = target_period/period_per_cycle - var ( - freq = uint64(CPUFrequency()) - phc = uint64(pwm.getPhaseCorrect()) - rhs = 16 * period * freq / ((1 + phc) * 1e9 * (1 + topStart)) // right-hand-side of equation, scaled so frac is not divided - whole = rhs / 16 - frac = rhs % 16 - ) - switch { - case whole > 0xff: - whole = 0xff - case whole == 0: - // whole calculation underflowed so setting to minimum - // permissible value in DIV_INT register. - whole = 1 - frac = 0 - } - - // Step 2 is acquiring a better top value. Clearing the equation: - // TOP = cycles / ( (DIVINT+DIVFRAC/16) * (CSRPHCorrect+1) ) - 1 - top := 16*period*freq/((1+phc)*1e9*(16*whole+frac)) - 1 - if top > maxTop { - top = maxTop - } - pwm.SetTop(uint32(top)) - pwm.setClockDiv(uint8(whole), uint8(frac)) - return nil -} - -// Int is integer value to reduce counting rate by. Must be greater than or equal to 1. DIV_INT is bits 4:11 (8 bits). -// frac's (DIV_FRAC) default value on reset is 0. Max value for frac is 15 (4 bits). This is known as a fixed-point -// fractional number. -// -// cycles = (TOP+1) * (CSRPHCorrect + 1) * (DIV_INT + DIV_FRAC/16) -func (pwm *pwmGroup) setClockDiv(Int, frac uint8) { - pwm.DIV.ReplaceBits((uint32(frac)<> pos) - return level -} - -func (pwm *pwmGroup) getWrap() (top uint32) { - return (pwm.TOP.Get() & rp.PWM_CH0_TOP_CH0_TOP_Msk) >> rp.PWM_CH0_TOP_CH0_TOP_Pos -} - -func (pwm *pwmGroup) getPhaseCorrect() (phCorrect uint32) { - return (pwm.CSR.Get() & rp.PWM_CH0_CSR_PH_CORRECT_Msk) >> rp.PWM_CH0_CSR_PH_CORRECT_Pos -} - -func (pwm *pwmGroup) getClockDiv() (Int, frac uint8) { - div := pwm.DIV.Get() - return uint8((div & rp.PWM_CH0_DIV_INT_Msk) >> rp.PWM_CH0_DIV_INT_Pos), uint8((div & rp.PWM_CH0_DIV_FRAC_Msk) >> rp.PWM_CH0_DIV_FRAC_Pos) -} - -// pwmGPIOToSlice Determine the PWM channel that is attached to the specified GPIO. -// gpio must be less than 30. Returns the PWM slice number that controls the specified GPIO. -func pwmGPIOToSlice(gpio Pin) (slicenum uint8) { - if is48Pin && gpio >= 32 { - return uint8(8 + ((gpio-32)/2)%4) - } - return (uint8(gpio) >> 1) & 7 -} - -// Determine the PWM channel that is attached to the specified GPIO. -// Each slice 0 to 7 has two channels, A and B. -func pwmGPIOToChannel(gpio Pin) (channel uint8) { - return uint8(gpio) & 1 -} diff --git a/emb/machine/machine_rp2_resets.go b/emb/machine/machine_rp2_resets.go deleted file mode 100644 index 245436c..0000000 --- a/emb/machine/machine_rp2_resets.go +++ /dev/null @@ -1,31 +0,0 @@ -//go:build rp2040 || rp2350 - -package machine - -import ( - "device/rp" - "unsafe" -) - -var resets = (*rp.RESETS_Type)(unsafe.Pointer(rp.RESETS)) - -// resetBlock resets hardware blocks specified -// by the bit pattern in bits. -func resetBlock(bits uint32) { - resets.RESET.SetBits(bits) -} - -// unresetBlock brings hardware blocks specified by the -// bit pattern in bits out of reset. -func unresetBlock(bits uint32) { - resets.RESET.ClearBits(bits) -} - -// unresetBlockWait brings specified hardware blocks -// specified by the bit pattern in bits -// out of reset and wait for completion. -func unresetBlockWait(bits uint32) { - unresetBlock(bits) - for !resets.RESET_DONE.HasBits(bits) { - } -} diff --git a/emb/machine/machine_rp2_rng.go b/emb/machine/machine_rp2_rng.go deleted file mode 100644 index e619f05..0000000 --- a/emb/machine/machine_rp2_rng.go +++ /dev/null @@ -1,41 +0,0 @@ -//go:build rp2040 || rp2350 - -// Implementation based on code located here: -// https://github.com/raspberrypi/pico-sdk/blob/master/src/rp2_common/pico_lwip/random.c - -package machine - -import ( - "device/rp" -) - -const numberOfCycles = 32 - -// GetRNG returns 32 bits of semi-random data based on ring oscillator. -// -// Unlike some other implementations of GetRNG, these random numbers are not -// cryptographically secure and must not be used for cryptographic operations -// (nonces, etc). -func GetRNG() (uint32, error) { - var val uint32 - for i := 0; i < 4; i++ { - val = (val << 8) | uint32(roscRandByte()) - } - return val, nil -} - -var randomByte uint8 - -func roscRandByte() uint8 { - var poly uint8 - for i := 0; i < numberOfCycles; i++ { - if randomByte&0x80 != 0 { - poly = 0x35 - } else { - poly = 0 - } - randomByte = ((randomByte << 1) | uint8(rp.ROSC.GetRANDOMBIT()) ^ poly) - // TODO: delay a little because the random bit is a little slow - } - return randomByte -} diff --git a/emb/machine/machine_rp2_spi.go b/emb/machine/machine_rp2_spi.go deleted file mode 100644 index d9cfc11..0000000 --- a/emb/machine/machine_rp2_spi.go +++ /dev/null @@ -1,404 +0,0 @@ -//go:build rp2040 || rp2350 - -package machine - -import ( - "device/rp" - "errors" - "unsafe" -) - -// SPI on the RP2040 -var ( - SPI0 = &SPI{ - Bus: rp.SPI0, - } - SPI1 = &SPI{ - Bus: rp.SPI1, - } -) - -// SPIConfig is used to store config info for SPI. -type SPIConfig struct { - Frequency uint32 - // LSB not supported on rp2040. - LSBFirst bool - // Mode's two most LSB are CPOL and CPHA. i.e. Mode==2 (0b10) is CPOL=1, CPHA=0 - Mode uint8 - // Serial clock pin - SCK Pin - // TX or Serial Data Out (MOSI if rp2040 is master) - SDO Pin - // RX or Serial Data In (MISO if rp2040 is master) - SDI Pin -} - -var ( - ErrLSBNotSupported = errors.New("SPI LSB unsupported on PL022") - ErrSPITimeout = errors.New("SPI timeout") - ErrSPIBaud = errors.New("SPI baud too low or above 66.5Mhz") - errSPIInvalidSDI = errors.New("invalid SPI SDI pin") - errSPIInvalidSDO = errors.New("invalid SPI SDO pin") - errSPIInvalidSCK = errors.New("invalid SPI SCK pin") -) - -type SPI struct { - Bus *rp.SPI0_Type -} - -// Tx handles read/write operation for SPI interface. Since SPI is a synchronous write/read -// interface, there must always be the same number of bytes written as bytes read. -// The Tx method knows about this, and offers a few different ways of calling it. -// -// This form sends the bytes in tx buffer, putting the resulting bytes read into the rx buffer. -// Note that the tx and rx buffers must be the same size: -// -// spi.Tx(tx, rx) -// -// This form sends the tx buffer, ignoring the result. Useful for sending "commands" that return zeros -// until all the bytes in the command packet have been received: -// -// spi.Tx(tx, nil) -// -// This form sends zeros, putting the result into the rx buffer. Good for reading a "result packet": -// -// spi.Tx(nil, rx) -// -// Remark: This implementation (RP2040) allows reading into buffer with a custom repeated -// value on tx. -// -// spi.Tx([]byte{0xff}, rx) // may cause unwanted heap allocations. -// -// This form sends 0xff and puts the result into rx buffer. Useful for reading from SD cards -// which require 0xff input on SI. -func (spi *SPI) Tx(w, r []byte) (err error) { - switch { - case w == nil: - // read only, so write zero and read a result. - err = spi.rx(r, 0) - case r == nil: - // write only - err = spi.tx(w) - case len(w) == 1 && len(r) > 1: - // Read with custom repeated value. - err = spi.rx(r, w[0]) - default: - // write/read - err = spi.txrx(w, r) - } - return err -} - -// Write a single byte and read a single byte from TX/RX FIFO. -func (spi *SPI) Transfer(w byte) (byte, error) { - for !spi.isWritable() { - } - - spi.Bus.SSPDR.Set(uint32(w)) - - for !spi.isReadable() { - } - return uint8(spi.Bus.SSPDR.Get()), nil -} - -func (spi *SPI) SetBaudRate(br uint32) error { - const maxBaud uint32 = 66.5 * MHz // max output frequency is 66.5MHz on rp2040. see Note page 527. - // Find smallest prescale value which puts output frequency in range of - // post-divide. Prescale is an even number from 2 to 254 inclusive. - var prescale, postdiv uint32 - freq := CPUFrequency() - for prescale = 2; prescale < 255; prescale += 2 { - if freq < (prescale+2)*256*br { - break - } - } - if prescale > 254 || br > maxBaud { - return ErrSPIBaud - } - // Find largest post-divide which makes output <= baudrate. Post-divide is - // an integer in the range 1 to 256 inclusive. - for postdiv = 256; postdiv > 1; postdiv-- { - if freq/(prescale*(postdiv-1)) > br { - break - } - } - spi.Bus.SSPCPSR.Set(prescale) - spi.Bus.SSPCR0.ReplaceBits((postdiv-1)<> rp.SPI0_SSPCR0_SCR_Pos) + 1 - return freqin / (prescale * postdiv) -} - -// Configure is intended to setup/initialize the SPI interface. -// Default baudrate of 4MHz is used if Frequency == 0. Default -// word length (data bits) is 8. -// Below is a list of GPIO pins corresponding to SPI0 bus on the rp2040: -// -// SI : 0, 4, 17 a.k.a RX and MISO (if rp2040 is master) -// SO : 3, 7, 19 a.k.a TX and MOSI (if rp2040 is master) -// SCK: 2, 6, 18 -// -// SPI1 bus GPIO pins: -// -// SI : 8, 12 -// SO : 11, 15 -// SCK: 10, 14 -// -// No pin configuration is needed of SCK, SDO and SDI needed after calling Configure. -func (spi *SPI) Configure(config SPIConfig) error { - const defaultBaud uint32 = 4 * MHz - if config.SCK == 0 && config.SDO == 0 && config.SDI == 0 { - // set default pins if config zero valued or invalid clock pin supplied. - switch spi.Bus { - case rp.SPI0: - config.SCK = SPI0_SCK_PIN - config.SDO = SPI0_SDO_PIN - config.SDI = SPI0_SDI_PIN - case rp.SPI1: - config.SCK = SPI1_SCK_PIN - config.SDO = SPI1_SDO_PIN - config.SDI = SPI1_SDI_PIN - } - } - var okSDI, okSDO, okSCK bool - switch spi.Bus { - case rp.SPI0: - okSDI = config.SDI == 0 || config.SDI == 4 || config.SDI == 16 || config.SDI == 20 - okSDO = config.SDO == 3 || config.SDO == 7 || config.SDO == 19 || config.SDO == 23 - okSCK = config.SCK == 2 || config.SCK == 6 || config.SCK == 18 || config.SCK == 22 - case rp.SPI1: - okSDI = config.SDI == 8 || config.SDI == 12 || config.SDI == 24 || config.SDI == 28 - okSDO = config.SDO == 11 || config.SDO == 15 || config.SDO == 27 - okSCK = config.SCK == 10 || config.SCK == 14 || config.SCK == 26 - } - - switch { - case !okSDI: - return errSPIInvalidSDI - case !okSDO: - return errSPIInvalidSDO - case !okSCK: - return errSPIInvalidSCK - } - - if config.Frequency == 0 { - config.Frequency = defaultBaud - } - // SPI pin configuration - config.SCK.setFunc(fnSPI) - config.SDO.setFunc(fnSPI) - config.SDI.setFunc(fnSPI) - - return spi.initSPI(config) -} - -func (spi *SPI) initSPI(config SPIConfig) (err error) { - spi.reset() - // LSB-first not supported on PL022: - if config.LSBFirst { - return ErrLSBNotSupported - } - err = spi.SetBaudRate(config.Frequency) - // Set SPI Format (CPHA and CPOL) and frame format (default is Motorola) - spi.setFormat(config.Mode) - - // Always enable DREQ signals -- harmless if DMA is not listening - spi.Bus.SSPDMACR.SetBits(rp.SPI0_SSPDMACR_TXDMAE | rp.SPI0_SSPDMACR_RXDMAE) - // Finally enable the SPI - spi.Bus.SSPCR1.SetBits(rp.SPI0_SSPCR1_SSE) - return err -} - -//go:inline -func (spi *SPI) setFormat(mode uint8) { - cpha := uint32(mode) & 1 - cpol := uint32(mode>>1) & 1 - spi.Bus.SSPCR0.ReplaceBits( - (cpha<>3].Set(p.ioIntBit(change)) -} - -// Basic interrupt setting via ioBANK0 for GPIO interrupts. -func (p Pin) setInterrupt(change PinChange, enabled bool) { - // Separate mask/force/status per-core, so check which core called, and - // set the relevant IRQ controls. - switch CurrentCore() { - case 0: - p.ctrlSetInterrupt(change, enabled, &ioBank0.proc0IRQctrl) - case 1: - p.ctrlSetInterrupt(change, enabled, &ioBank0.proc1IRQctrl) - } -} - -// ctrlSetInterrupt acknowledges any pending interrupt and enables or disables -// the interrupt for a given IRQ control bank (IOBANK, DormantIRQ, QSPI). -// -// pico-sdk calls this the _gpio_set_irq_enabled, not to be confused with -// gpio_set_irq_enabled (no leading underscore). -func (p Pin) ctrlSetInterrupt(change PinChange, enabled bool, base *irqCtrl) { - p.acknowledgeInterrupt(change) - enReg := &base.intE[p>>3] - if enabled { - enReg.SetBits(p.ioIntBit(change)) - } else { - enReg.ClearBits(p.ioIntBit(change)) - } -} diff --git a/emb/machine/machine_rp2_timer.go b/emb/machine/machine_rp2_timer.go deleted file mode 100644 index a78ed70..0000000 --- a/emb/machine/machine_rp2_timer.go +++ /dev/null @@ -1,103 +0,0 @@ -//go:build rp2040 || rp2350 - -package machine - -import ( - "device/arm" - "runtime/interrupt" - "runtime/volatile" -) - -const numTimers = 4 - -// Alarm0 is reserved for sleeping by tinygo runtime code for RP2040. -// Alarm0 is also IRQ0 -const sleepAlarm = 0 -const sleepAlarmIRQ = 0 - -// The minimum sleep duration in μs (ticks) -const minSleep = 10 - -type timerType struct { - timeHW volatile.Register32 - timeLW volatile.Register32 - timeHR volatile.Register32 - timeLR volatile.Register32 - alarm [numTimers]volatile.Register32 - armed volatile.Register32 - timeRawH volatile.Register32 - timeRawL volatile.Register32 - dbgPause volatile.Register32 - pause volatile.Register32 - locked [rp2350ExtraReg]volatile.Register32 - source [rp2350ExtraReg]volatile.Register32 - intR volatile.Register32 - intE volatile.Register32 - intF volatile.Register32 - intS volatile.Register32 -} - -// TimeElapsed returns time elapsed since power up, in microseconds. -func (tmr *timerType) timeElapsed() (us uint64) { - // Need to make sure that the upper 32 bits of the timer - // don't change, so read that first - hi := tmr.timeRawH.Get() - var lo, nextHi uint32 - for { - // Read the lower 32 bits - lo = tmr.timeRawL.Get() - // Now read the upper 32 bits again and - // check that it hasn't incremented. If it has, loop around - // and read the lower 32 bits again to get an accurate value - nextHi = tmr.timeRawH.Get() - if hi == nextHi { - break - } - hi = nextHi - } - return uint64(hi)<<32 | uint64(lo) -} - -// lightSleep will put the processor into a sleep state a short period -// (up to approx 72mins per RP2040 datasheet, 4.6.3. Alarms). -// -// This function is a 'light' sleep and will return early if another -// interrupt or event triggers. This is intentional since the -// primary use-case is for use by the TinyGo scheduler which will -// re-sleep if needed. -func (tmr *timerType) lightSleep(us uint64) { - // minSleep is a way to avoid race conditions for short - // sleeps by ensuring there is enough time to setup the - // alarm before sleeping. For very short sleeps, this - // effectively becomes a 'busy loop'. - if us < minSleep { - return - } - - // Interrupt handler is essentially a no-op, we're just relying - // on the side-effect of waking the CPU from "wfe" - intr := interrupt.New(sleepAlarmIRQ, func(interrupt.Interrupt) { - // Clear the IRQ - timer.intR.Set(1 << sleepAlarm) - }) - - // Reset interrupt flag - tmr.intR.Set(1 << sleepAlarm) - - // Enable interrupt - tmr.intE.SetBits(1 << sleepAlarm) - intr.Enable() - - // Only the low 32 bits of time can be used for alarms - target := uint64(tmr.timeRawL.Get()) + us - tmr.alarm[sleepAlarm].Set(uint32(target)) - - // Wait for sleep (or any other) interrupt - arm.Asm("wfe") - - // Disarm timer - tmr.armed.Set(1 << sleepAlarm) - - // Disable interrupt - intr.Disable() -} diff --git a/emb/machine/machine_rp2_uart.go b/emb/machine/machine_rp2_uart.go deleted file mode 100644 index 03ebb9d..0000000 --- a/emb/machine/machine_rp2_uart.go +++ /dev/null @@ -1,159 +0,0 @@ -//go:build rp2040 || rp2350 - -package machine - -import ( - "device/rp" - "runtime/interrupt" -) - -// UART on the RP2040. -type UART struct { - Buffer *RingBuffer - Bus *rp.UART0_Type - Interrupt interrupt.Interrupt -} - -// Configure the UART. -func (uart *UART) Configure(config UARTConfig) error { - initUART(uart) - - // Default baud rate to 115200. - if config.BaudRate == 0 { - config.BaudRate = 115200 - } - - // Use default pins if pins are not set. - if config.TX == 0 && config.RX == 0 { - // use default pins - config.TX = UART_TX_PIN - config.RX = UART_RX_PIN - } - - uart.SetBaudRate(config.BaudRate) - - // default to 8-1-N - uart.SetFormat(8, 1, ParityNone) - - // Enable the UART, both TX and RX - settings := uint32(rp.UART0_UARTCR_UARTEN | - rp.UART0_UARTCR_RXE | - rp.UART0_UARTCR_TXE) - const bits = rp.UART0_UARTCR_UARTEN | rp.UART0_UARTCR_TXE - if config.RTS != 0 { - settings |= rp.UART0_UARTCR_RTSEN - } - if config.CTS != 0 { - settings |= rp.UART0_UARTCR_CTSEN - } - - uart.Bus.UARTCR.SetBits(settings) - - // set GPIO mux to UART for the pins - if config.TX != NoPin { - config.TX.Configure(PinConfig{Mode: PinUART}) - } - if config.RX != NoPin { - config.RX.Configure(PinConfig{Mode: PinUART}) - } - if config.RTS != 0 { - config.RTS.Configure(PinConfig{Mode: PinOutput}) - } - if config.CTS != 0 { - config.CTS.Configure(PinConfig{Mode: PinInput}) - } - - // Enable RX IRQ. - uart.Interrupt.SetPriority(0x80) - uart.Interrupt.Enable() - - // Setup interrupt on receive. - uart.Bus.UARTIMSC.Set(rp.UART0_UARTIMSC_RXIM) - - return nil -} - -// SetBaudRate sets the baudrate to be used for the UART. -func (uart *UART) SetBaudRate(br uint32) { - div := 8 * CPUFrequency() / br - - ibrd := div >> 7 - var fbrd uint32 - - switch { - case ibrd == 0: - ibrd = 1 - fbrd = 0 - case ibrd >= 65535: - ibrd = 65535 - fbrd = 0 - default: - fbrd = ((div & 0x7f) + 1) / 2 - } - - // set PL011 baud divisor registers - uart.Bus.UARTIBRD.Set(ibrd) - uart.Bus.UARTFBRD.Set(fbrd) - - // PL011 needs a (dummy) line control register write. - // See https://github.com/raspberrypi/pico-sdk/blob/master/src/rp2_common/hardware_uart/uart.c#L93-L95 - uart.Bus.UARTLCR_H.SetBits(0) -} - -// WriteByte writes a byte of data to the UART. -func (uart *UART) writeByte(c byte) error { - // wait until buffer is not full - for uart.Bus.UARTFR.HasBits(rp.UART0_UARTFR_TXFF) { - gosched() - } - - // write data - uart.Bus.UARTDR.Set(uint32(c)) - return nil -} - -func (uart *UART) flush() { - for uart.Bus.UARTFR.HasBits(rp.UART0_UARTFR_BUSY) { - gosched() - } -} - -// SetFormat for number of data bits, stop bits, and parity for the UART. -func (uart *UART) SetFormat(databits, stopbits uint8, parity UARTParity) error { - var pen, pev uint8 - if parity != ParityNone { - pen = rp.UART0_UARTLCR_H_PEN - } - if parity == ParityEven { - pev = rp.UART0_UARTLCR_H_EPS - } - uart.Bus.UARTLCR_H.SetBits(uint32((databits-5)< usb.EndpointPacketSize { - count = usb.EndpointPacketSize - - sendOnEP0DATADONE.offset = count - sendOnEP0DATADONE.data = data - } else { - sendOnEP0DATADONE.offset = 0 - } - epXdata0[ep] = true - } - - sendViaEPIn(ep, data, count) -} - -func ReceiveUSBControlPacket() ([cdcLineInfoSize]byte, error) { - var b [cdcLineInfoSize]byte - ep := 0 - - for !_usbDPSRAM.EPxBufferControl[ep].Out.HasBits(usbBuf0CtrlFull) { - // TODO: timeout - } - - ctrl := _usbDPSRAM.EPxBufferControl[ep].Out.Get() - _usbDPSRAM.EPxBufferControl[ep].Out.Set(usbBufferLen & usbBuf0CtrlLenMask) - sz := ctrl & usbBuf0CtrlLenMask - - copy(b[:], _usbDPSRAM.EPxBuffer[ep].Buffer0[:sz]) - - _usbDPSRAM.EPxBufferControl[ep].Out.SetBits(usbBuf0CtrlData1Pid) - _usbDPSRAM.EPxBufferControl[ep].Out.SetBits(usbBuf0CtrlAvail) - - return b, nil -} - -func handleEndpointRx(ep uint32) []byte { - ctrl := _usbDPSRAM.EPxBufferControl[ep].Out.Get() - _usbDPSRAM.EPxBufferControl[ep].Out.Set(usbBufferLen & usbBuf0CtrlLenMask) - sz := ctrl & usbBuf0CtrlLenMask - - return _usbDPSRAM.EPxBuffer[ep].Buffer0[:sz] -} - -// AckUsbOutTransfer is called to acknowledge the completion of a USB OUT transfer. -func AckUsbOutTransfer(ep uint32) { - ep = ep & 0x7F - setEPDataPID(ep, !epXdata0[ep]) -} - -// Set the USB endpoint Packet ID to DATA0 or DATA1. -func setEPDataPID(ep uint32, dataOne bool) { - epXdata0[ep] = dataOne - if epXdata0[ep] || ep == 0 { - _usbDPSRAM.EPxBufferControl[ep].Out.SetBits(usbBuf0CtrlData1Pid) - } - - _usbDPSRAM.EPxBufferControl[ep].Out.SetBits(usbBuf0CtrlAvail) -} - -func SendZlp() { - sendUSBPacket(0, []byte{}, 0) -} - -func sendViaEPIn(ep uint32, data []byte, count int) { - // Prepare buffer control register value - val := uint32(count) | usbBuf0CtrlAvail - - // DATA0 or DATA1 - epXdata0[ep&0x7F] = !epXdata0[ep&0x7F] - if !epXdata0[ep&0x7F] { - val |= usbBuf0CtrlData1Pid - } - - // Mark as full - val |= usbBuf0CtrlFull - - copy(_usbDPSRAM.EPxBuffer[ep&0x7F].Buffer0[:], data[:count]) - _usbDPSRAM.EPxBufferControl[ep&0x7F].In.Set(val) -} - -// Set ENDPOINT_HALT/stall status on a USB IN endpoint. -func (dev *USBDevice) SetStallEPIn(ep uint32) { - ep = ep & 0x7F - // Prepare buffer control register value - if ep == 0 { - armEPZeroStall() - } - val := uint32(usbBuf0CtrlFull) - _usbDPSRAM.EPxBufferControl[ep].In.Set(val) - val |= uint32(usbBuf0CtrlStall) - _usbDPSRAM.EPxBufferControl[ep].In.Set(val) -} - -// Set ENDPOINT_HALT/stall status on a USB OUT endpoint. -func (dev *USBDevice) SetStallEPOut(ep uint32) { - ep = ep & 0x7F - if ep == 0 { - panic("SetStallEPOut: EP0 OUT not valid") - } - val := uint32(usbBuf0CtrlStall) - _usbDPSRAM.EPxBufferControl[ep].Out.Set(val) -} - -// Clear the ENDPOINT_HALT/stall on a USB IN endpoint. -func (dev *USBDevice) ClearStallEPIn(ep uint32) { - ep = ep & 0x7F - val := uint32(usbBuf0CtrlStall) - _usbDPSRAM.EPxBufferControl[ep].In.ClearBits(val) - if epXPIDReset[ep] { - // Reset the PID to DATA0 - setEPDataPID(ep, false) - } -} - -// Clear the ENDPOINT_HALT/stall on a USB OUT endpoint. -func (dev *USBDevice) ClearStallEPOut(ep uint32) { - ep = ep & 0x7F - val := uint32(usbBuf0CtrlStall) - _usbDPSRAM.EPxBufferControl[ep].Out.ClearBits(val) - if epXPIDReset[ep] { - // Reset the PID to DATA0 - setEPDataPID(ep, false) - } -} - -type usbDPSRAM struct { - // Note that EPxControl[0] is not EP0Control but 8-byte setup data. - EPxControl [16]usbEndpointControlRegister - - EPxBufferControl [16]usbBufferControlRegister - - EPxBuffer [16]usbBuffer -} - -type usbEndpointControlRegister struct { - In volatile.Register32 - Out volatile.Register32 -} -type usbBufferControlRegister struct { - In volatile.Register32 - Out volatile.Register32 -} - -type usbBuffer struct { - Buffer0 [usbBufferLen]byte - Buffer1 [usbBufferLen]byte -} - -var ( - _usbDPSRAM = (*usbDPSRAM)(unsafe.Pointer(uintptr(0x50100000))) - epXdata0 [16]bool - epXPIDReset [16]bool - setupBytes [8]byte -) - -func (d *usbDPSRAM) setupBytes() []byte { - - data := d.EPxControl[usb.CONTROL_ENDPOINT].In.Get() - setupBytes[0] = byte(data) - setupBytes[1] = byte(data >> 8) - setupBytes[2] = byte(data >> 16) - setupBytes[3] = byte(data >> 24) - - data = d.EPxControl[usb.CONTROL_ENDPOINT].Out.Get() - setupBytes[4] = byte(data) - setupBytes[5] = byte(data >> 8) - setupBytes[6] = byte(data >> 16) - setupBytes[7] = byte(data >> 24) - - return setupBytes[:] -} - -func (d *usbDPSRAM) clear() { - for i := 0; i < len(d.EPxControl); i++ { - d.EPxControl[i].In.Set(0) - d.EPxControl[i].Out.Set(0) - d.EPxBufferControl[i].In.Set(0) - d.EPxBufferControl[i].Out.Set(0) - } -} - -const ( - // DPRAM : Endpoint control register - usbEpControlEnable = 0x80000000 - usbEpControlDoubleBuffered = 0x40000000 - usbEpControlInterruptPerBuff = 0x20000000 - usbEpControlInterruptPerDoubleBuff = 0x10000000 - usbEpControlEndpointType = 0x0c000000 - usbEpControlInterruptOnStall = 0x00020000 - usbEpControlInterruptOnNak = 0x00010000 - usbEpControlBufferAddress = 0x0000ffff - - usbEpControlEndpointTypeControl = 0x00000000 - usbEpControlEndpointTypeISO = 0x04000000 - usbEpControlEndpointTypeBulk = 0x08000000 - usbEpControlEndpointTypeInterrupt = 0x0c000000 - - // Endpoint buffer control bits - usbBuf1CtrlFull = 0x80000000 - usbBuf1CtrlLast = 0x40000000 - usbBuf1CtrlData0Pid = 0x20000000 - usbBuf1CtrlData1Pid = 0x00000000 - usbBuf1CtrlSel = 0x10000000 - usbBuf1CtrlStall = 0x08000000 - usbBuf1CtrlAvail = 0x04000000 - usbBuf1CtrlLenMask = 0x03FF0000 - usbBuf0CtrlFull = 0x00008000 - usbBuf0CtrlLast = 0x00004000 - usbBuf0CtrlData0Pid = 0x00000000 - usbBuf0CtrlData1Pid = 0x00002000 - usbBuf0CtrlSel = 0x00001000 - usbBuf0CtrlStall = 0x00000800 - usbBuf0CtrlAvail = 0x00000400 - usbBuf0CtrlLenMask = 0x000003FF - - usbBufferLen = 64 -) diff --git a/emb/machine/machine_rp2_watchdog.go b/emb/machine/machine_rp2_watchdog.go deleted file mode 100644 index f776c5c..0000000 --- a/emb/machine/machine_rp2_watchdog.go +++ /dev/null @@ -1,62 +0,0 @@ -//go:build rp2040 || rp2350 - -package machine - -import ( - "device/rp" -) - -// Watchdog provides access to the hardware watchdog available -// in the RP2040. -var Watchdog = &watchdogImpl{} - -const ( - // WatchdogMaxTimeout in milliseconds (approx 8.3s). - // - // Nominal 1us per watchdog tick, 24-bit counter, - // but due to errata two ticks consumed per 1us. - // See: Errata RP2040-E1 - WatchdogMaxTimeout = (rp.WATCHDOG_LOAD_LOAD_Msk / 1000) / 2 -) - -type watchdogImpl struct { - // The value to reset the counter to on each Update - loadValue uint32 -} - -// Configure the watchdog. -// -// This method should not be called after the watchdog is started and on -// some platforms attempting to reconfigure after starting the watchdog -// is explicitly forbidden / will not work. -func (wd *watchdogImpl) Configure(config WatchdogConfig) error { - // x2 due to errata RP2040-E1 - wd.loadValue = config.TimeoutMillis * 1000 * 2 - if wd.loadValue > rp.WATCHDOG_LOAD_LOAD_Msk { - wd.loadValue = rp.WATCHDOG_LOAD_LOAD_Msk - } - - rp.WATCHDOG.CTRL.ClearBits(rp.WATCHDOG_CTRL_ENABLE) - - // Reset everything apart from ROSC and XOSC - rp.PSM.WDSEL.Set(0x0001ffff &^ (rp.PSM_WDSEL_ROSC | rp.PSM_WDSEL_XOSC)) - - // Pause watchdog during debug - rp.WATCHDOG.CTRL.SetBits(rp.WATCHDOG_CTRL_PAUSE_DBG0 | rp.WATCHDOG_CTRL_PAUSE_DBG1 | rp.WATCHDOG_CTRL_PAUSE_JTAG) - - // Load initial counter - rp.WATCHDOG.LOAD.Set(wd.loadValue) - - return nil -} - -// Starts the watchdog. -func (wd *watchdogImpl) Start() error { - rp.WATCHDOG.CTRL.SetBits(rp.WATCHDOG_CTRL_ENABLE) - return nil -} - -// Update the watchdog, indicating that the app is healthy. -func (wd *watchdogImpl) Update() { - rp.WATCHDOG.LOAD.Set(wd.loadValue) -} diff --git a/emb/machine/machine_rp2_xosc.go b/emb/machine/machine_rp2_xosc.go deleted file mode 100644 index c9ce583..0000000 --- a/emb/machine/machine_rp2_xosc.go +++ /dev/null @@ -1,47 +0,0 @@ -//go:build rp2040 || rp2350 - -package machine - -import ( - "device/rp" - "runtime/volatile" - "unsafe" -) - -// On some boards, the XOSC can take longer than usual to stabilize. On such -// boards, this is needed to avoid a hard fault on boot/reset. Refer to -// PICO_XOSC_STARTUP_DELAY_MULTIPLIER in the Pico SDK for additional details. -const XOSC_STARTUP_DELAY_MULTIPLIER = 64 - -type xoscType struct { - ctrl volatile.Register32 - status volatile.Register32 - dormant volatile.Register32 - startup volatile.Register32 - reserved [3 - 3*rp2350ExtraReg]volatile.Register32 - count volatile.Register32 -} - -var xosc = (*xoscType)(unsafe.Pointer(rp.XOSC)) - -// init initializes the crystal oscillator system. -// -// This function will block until the crystal oscillator has stabilised. -func (osc *xoscType) init() { - // Assumes 1-15 MHz input - if xoscFreq > 15 { - panic("xosc frequency cannot be greater than 15MHz") - } - osc.ctrl.Set(rp.XOSC_CTRL_FREQ_RANGE_1_15MHZ) - - // Set xosc startup delay - delay := (((xoscFreq * MHz) / 1000) + 128) / 256 * XOSC_STARTUP_DELAY_MULTIPLIER - osc.startup.Set(uint32(delay)) - - // Set the enable bit now that we have set freq range and startup delay - osc.ctrl.SetBits(rp.XOSC_CTRL_ENABLE_ENABLE << rp.XOSC_CTRL_ENABLE_Pos) - - // Wait for xosc to be stable - for !osc.status.HasBits(rp.XOSC_STATUS_STABLE) { - } -} diff --git a/emb/machine/machine_stm32.go b/emb/machine/machine_stm32.go deleted file mode 100644 index 1edaa2c..0000000 --- a/emb/machine/machine_stm32.go +++ /dev/null @@ -1,104 +0,0 @@ -//go:build stm32 - -package machine - -import ( - "device/stm32" - - "runtime/volatile" - "unsafe" -) - -const deviceName = stm32.Device - -// Peripheral abstraction layer for the stm32. - -const ( - portA Pin = iota * 16 - portB - portC - portD - portE - portF - portG - portH - portI - portJ - portK -) - -// Peripheral operations sequence: -// 1. Enable the clock to the alternate function. -// 2. Enable clock to corresponding GPIO -// 3. Attach the alternate function. -// 4. Configure the input-output port and pins (of the corresponding GPIOx) to match the AF . -// 5. If desired enable the nested vector interrupt control to generate interrupts. -// 6. Program the AF/peripheral for the required configuration (eg baud rate for a USART) . - -// Given that the stm32 family has the AF and GPIO on different registers based on the chip, -// use the main function here for configuring, and use hooks in the more specific chip -// definition files -// Also, the stm32f1xx series handles things differently from the stm32f0/2/3/4 - -// ---------- General pin operations ---------- -type PinChange uint8 - -const ( - PinRising PinChange = 1 << iota - PinFalling - PinToggle = PinRising | PinFalling -) - -// Set the pin to high or low. -// Warning: only use this on an output pin! -func (p Pin) Set(high bool) { - port := p.getPort() - pin := uint8(p) % 16 - if high { - port.BSRR.Set(1 << pin) - } else { - port.BSRR.Set(1 << (pin + 16)) - } -} - -// Get returns the current value of a GPIO pin when the pin is configured as an -// input or as an output. -func (p Pin) Get() bool { - port := p.getPort() - pin := uint8(p) % 16 - val := port.IDR.Get() & (1 << pin) - return (val > 0) -} - -// PortMaskSet returns the register and mask to enable a given GPIO pin. This -// can be used to implement bit-banged drivers. -func (p Pin) PortMaskSet() (*uint32, uint32) { - port := p.getPort() - pin := uint8(p) % 16 - return &port.BSRR.Reg, 1 << pin -} - -// PortMaskClear returns the register and mask to disable a given port. This can -// be used to implement bit-banged drivers. -func (p Pin) PortMaskClear() (*uint32, uint32) { - port := p.getPort() - pin := uint8(p) % 16 - return &port.BSRR.Reg, 1 << (pin + 16) -} - -var deviceID [12]byte - -// DeviceID returns an identifier that is unique within -// a particular chipset. -// -// The identity is one burnt into the MCU itself. -// -// The length of the device ID for STM32 is 12 bytes (96 bits). -func DeviceID() []byte { - for i := 0; i < len(deviceID); i++ { - word := (*volatile.Register32)(unsafe.Pointer(deviceIDAddr[i/4])).Get() - deviceID[i] = byte(word >> ((i % 4) * 8)) - } - - return deviceID[:] -} diff --git a/emb/machine/machine_stm32_adc_f1.go b/emb/machine/machine_stm32_adc_f1.go deleted file mode 100644 index 7076bdd..0000000 --- a/emb/machine/machine_stm32_adc_f1.go +++ /dev/null @@ -1,90 +0,0 @@ -//go:build stm32f103 - -package machine - -import ( - "device/stm32" - "unsafe" -) - -const ( - Cycles_1_5 = 0x0 - Cycles_7_5 = 0x1 - Cycles_13_5 = 0x2 - Cycles_28_5 = 0x3 - Cycles_41_5 = 0x4 - Cycles_55_5 = 0x5 - Cycles_71_5 = 0x6 - Cycles_239_5 = 0x7 -) - -// InitADC initializes the registers needed for ADC1. -func InitADC() { - // Enable ADC clock - enableAltFuncClock(unsafe.Pointer(stm32.ADC1)) - - // enable - stm32.ADC1.CR2.SetBits(stm32.ADC_CR2_ADON | stm32.ADC_CR2_ALIGN) - - return -} - -// Configure configures an ADC pin to be able to read analog data. -func (a ADC) Configure(ADCConfig) { - a.Pin.Configure(PinConfig{Mode: PinInputModeAnalog}) - - // set sample time - ch := a.getChannel() - if ch > 9 { - stm32.ADC1.SMPR1.SetBits(Cycles_28_5 << (ch - 10) * stm32.ADC_SMPR1_SMP11_Pos) - } else { - stm32.ADC1.SMPR2.SetBits(Cycles_28_5 << (ch * stm32.ADC_SMPR2_SMP1_Pos)) - } - - return -} - -// Get returns the current value of a ADC pin in the range 0..0xffff. -// TODO: DMA based implementation. -func (a ADC) Get() uint16 { - // set rank - ch := uint32(a.getChannel()) - stm32.ADC1.SetSQR3_SQ1(ch) - - // start conversion - stm32.ADC1.CR2.SetBits(stm32.ADC_CR2_ADON) - - // wait for conversion to complete - for !stm32.ADC1.SR.HasBits(stm32.ADC_SR_EOC) { - } - - // read result as 16 bit value - return uint16(stm32.ADC1.DR.Get()) -} - -func (a ADC) getChannel() uint8 { - switch a.Pin { - case PA0: - return 0 - case PA1: - return 1 - case PA2: - return 2 - case PA3: - return 3 - case PA4: - return 4 - case PA5: - return 5 - case PA6: - return 6 - case PA7: - return 7 - case PB0: - return 8 - case PB1: - return 9 - } - - return 0 -} diff --git a/emb/machine/machine_stm32_adc_f4.go b/emb/machine/machine_stm32_adc_f4.go deleted file mode 100644 index df4984c..0000000 --- a/emb/machine/machine_stm32_adc_f4.go +++ /dev/null @@ -1,114 +0,0 @@ -//go:build stm32f4 - -package machine - -import ( - "device/stm32" - "unsafe" -) - -// InitADC initializes the registers needed for ADC1. -func InitADC() { - // Enable ADC clock - enableAltFuncClock(unsafe.Pointer(stm32.ADC1)) - - // stop scan, and clear scan resolution - stm32.ADC1.CR1.ClearBits(stm32.ADC_CR1_SCAN | stm32.ADC_CR1_RES_Msk) - - // set conversion mode and resolution - stm32.ADC1.CR1.SetBits(stm32.ADC_CR1_RES_TwelveBit) - - // clear CONT, ALIGN, EXTEN and EXTSEL bits from CR2 - stm32.ADC1.CR2.ClearBits(stm32.ADC_CR2_CONT | stm32.ADC_CR2_ALIGN | stm32.ADC_CR2_EXTEN_Msk | stm32.ADC_CR2_EXTSEL_Msk) - - // set CONT, ALIGN, EXTEN and EXTSEL bits from CR2 - stm32.ADC1.CR2.SetBits(stm32.ADC_CR2_CONT_Single | stm32.ADC_CR2_ALIGN_Right) - - stm32.ADC1.SQR1.ClearBits(stm32.ADC_SQR1_L_Msk) - stm32.ADC1.SQR1.SetBits(2 << stm32.ADC_SQR1_L_Pos) // 2 means 3 conversions - - // enable - stm32.ADC1.CR2.SetBits(stm32.ADC_CR2_ADON) - - return -} - -// Configure configures an ADC pin to be able to read analog data. -func (a ADC) Configure(ADCConfig) { - a.Pin.ConfigureAltFunc(PinConfig{Mode: PinInputAnalog}, 0) - - // set sample time - ch := a.getChannel() - if ch > 9 { - stm32.ADC1.SMPR1.SetBits(stm32.ADC_SMPR1_SMP11_Cycles84 << (ch - 10) * stm32.ADC_SMPR1_SMP11_Pos) - } else { - stm32.ADC1.SMPR2.SetBits(stm32.ADC_SMPR2_SMP1_Cycles84 << (ch * stm32.ADC_SMPR2_SMP1_Pos)) - } - - return -} - -// Get returns the current value of a ADC pin in the range 0..0xffff. -// TODO: DMA based implementation. -func (a ADC) Get() uint16 { - // set rank - ch := uint32(a.getChannel()) - stm32.ADC1.SQR3.SetBits(ch) - - // start conversion - stm32.ADC1.CR2.SetBits(stm32.ADC_CR2_SWSTART) - - // wait for conversion to complete - for !stm32.ADC1.SR.HasBits(stm32.ADC_SR_EOC) { - } - - // read 12-bit result as 16 bit value - result := uint16(stm32.ADC1.DR.Get()) << 4 - - // clear flag - stm32.ADC1.SR.ClearBits(stm32.ADC_SR_EOC) - - // clear rank - stm32.ADC1.SQR3.ClearBits(ch) - - return result -} - -func (a ADC) getChannel() uint8 { - switch a.Pin { - case PA0: - return 0 - case PA1: - return 1 - case PA2: - return 2 - case PA3: - return 3 - case PA4: - return 4 - case PA5: - return 5 - case PA6: - return 6 - case PA7: - return 7 - case PB0: - return 8 - case PB1: - return 9 - case PC0: - return 10 - case PC1: - return 11 - case PC2: - return 12 - case PC3: - return 13 - case PC4: - return 14 - case PC5: - return 15 - } - - return 0 -} diff --git a/emb/machine/machine_stm32_exti_afio.go b/emb/machine/machine_stm32_exti_afio.go deleted file mode 100644 index 89a9506..0000000 --- a/emb/machine/machine_stm32_exti_afio.go +++ /dev/null @@ -1,27 +0,0 @@ -//go:build stm32f1 - -package machine - -import ( - "device/stm32" - "runtime/volatile" -) - -func getEXTIConfigRegister(pin uint8) *volatile.Register32 { - switch (pin & 0xf) / 4 { - case 0: - return &stm32.AFIO.EXTICR1 - case 1: - return &stm32.AFIO.EXTICR2 - case 2: - return &stm32.AFIO.EXTICR3 - case 3: - return &stm32.AFIO.EXTICR4 - } - return nil -} - -func enableEXTIConfigRegisters() { - // Enable AFIO - stm32.RCC.APB2ENR.SetBits(stm32.RCC_APB2ENR_AFIOEN) -} diff --git a/emb/machine/machine_stm32_exti_exti.go b/emb/machine/machine_stm32_exti_exti.go deleted file mode 100644 index 874a043..0000000 --- a/emb/machine/machine_stm32_exti_exti.go +++ /dev/null @@ -1,26 +0,0 @@ -//go:build stm32l5 - -package machine - -import ( - "device/stm32" - "runtime/volatile" -) - -func getEXTIConfigRegister(pin uint8) *volatile.Register32 { - switch (pin & 0xf) / 4 { - case 0: - return &stm32.EXTI.EXTICR1 - case 1: - return &stm32.EXTI.EXTICR2 - case 2: - return &stm32.EXTI.EXTICR3 - case 3: - return &stm32.EXTI.EXTICR4 - } - return nil -} - -func enableEXTIConfigRegisters() { - // No-op -} diff --git a/emb/machine/machine_stm32_exti_syscfg.go b/emb/machine/machine_stm32_exti_syscfg.go deleted file mode 100644 index f7c91f8..0000000 --- a/emb/machine/machine_stm32_exti_syscfg.go +++ /dev/null @@ -1,27 +0,0 @@ -//go:build stm32 && !stm32f1 && !stm32l5 && !stm32wlx - -package machine - -import ( - "device/stm32" - "runtime/volatile" -) - -func getEXTIConfigRegister(pin uint8) *volatile.Register32 { - switch (pin & 0xf) / 4 { - case 0: - return &stm32.SYSCFG.EXTICR1 - case 1: - return &stm32.SYSCFG.EXTICR2 - case 2: - return &stm32.SYSCFG.EXTICR3 - case 3: - return &stm32.SYSCFG.EXTICR4 - } - return nil -} - -func enableEXTIConfigRegisters() { - // Enable SYSCFG - stm32.RCC.APB2ENR.SetBits(stm32.RCC_APB2ENR_SYSCFGEN) -} diff --git a/emb/machine/machine_stm32_exti_syscfg_noenable.go b/emb/machine/machine_stm32_exti_syscfg_noenable.go deleted file mode 100644 index 85f47fa..0000000 --- a/emb/machine/machine_stm32_exti_syscfg_noenable.go +++ /dev/null @@ -1,26 +0,0 @@ -//go:build stm32wlx - -package machine - -import ( - "device/stm32" - "runtime/volatile" -) - -func getEXTIConfigRegister(pin uint8) *volatile.Register32 { - switch (pin & 0xf) / 4 { - case 0: - return &stm32.SYSCFG.EXTICR1 - case 1: - return &stm32.SYSCFG.EXTICR2 - case 2: - return &stm32.SYSCFG.EXTICR3 - case 3: - return &stm32.SYSCFG.EXTICR4 - } - return nil -} - -func enableEXTIConfigRegisters() { - // No registers to enable -} diff --git a/emb/machine/machine_stm32_flash.go b/emb/machine/machine_stm32_flash.go deleted file mode 100644 index 280dc89..0000000 --- a/emb/machine/machine_stm32_flash.go +++ /dev/null @@ -1,115 +0,0 @@ -//go:build stm32f4 || stm32l4 || stm32wlx - -package machine - -import ( - "device/stm32" - - "unsafe" -) - -// compile-time check for ensuring we fulfill BlockDevice interface -var _ BlockDevice = flashBlockDevice{} - -var Flash flashBlockDevice - -type flashBlockDevice struct { -} - -// ReadAt reads the given number of bytes from the block device. -func (f flashBlockDevice) ReadAt(p []byte, off int64) (n int, err error) { - if FlashDataStart()+uintptr(off)+uintptr(len(p)) > FlashDataEnd() { - return 0, errFlashCannotReadPastEOF - } - - data := unsafe.Slice((*byte)(unsafe.Pointer(FlashDataStart()+uintptr(off))), len(p)) - copy(p, data) - - return len(p), nil -} - -// WriteAt writes the given number of bytes to the block device. -// Only double-word (64 bits) length data can be programmed. See rm0461 page 78. -// If the length of p is not long enough it will be padded with 0xFF bytes. -// This method assumes that the destination is already erased. -func (f flashBlockDevice) WriteAt(p []byte, off int64) (n int, err error) { - if FlashDataStart()+uintptr(off)+uintptr(len(p)) > FlashDataEnd() { - return 0, errFlashCannotWritePastEOF - } - - unlockFlash() - defer lockFlash() - - p = flashPad(p, int(f.WriteBlockSize())) - return writeFlashData(FlashDataStart()+uintptr(off), p) -} - -// Size returns the number of bytes in this block device. -func (f flashBlockDevice) Size() int64 { - return int64(FlashDataEnd() - FlashDataStart()) -} - -// WriteBlockSize returns the block size in which data can be written to -// memory. It can be used by a client to optimize writes, non-aligned writes -// should always work correctly. -func (f flashBlockDevice) WriteBlockSize() int64 { - return writeBlockSize -} - -func eraseBlockSize() int64 { - return eraseBlockSizeValue -} - -// EraseBlockSize returns the smallest erasable area on this particular chip -// in bytes. This is used for the block size in EraseBlocks. -// It must be a power of two, and may be as small as 1. A typical size is 4096. -// TODO: correctly handle processors that have differently sized blocks -// in different areas of memory like the STM32F40x and STM32F1x. -func (f flashBlockDevice) EraseBlockSize() int64 { - return eraseBlockSize() -} - -// EraseBlocks erases the given number of blocks. An implementation may -// transparently coalesce ranges of blocks into larger bundles if the chip -// supports this. The start and len parameters are in block numbers, use -// EraseBlockSize to map addresses to blocks. -// Note that block 0 should map to the address of FlashDataStart(). -func (f flashBlockDevice) EraseBlocks(start, len int64) error { - var address uintptr = uintptr(start*f.EraseBlockSize()) + FlashDataStart() - blk := int64(address-uintptr(memoryStart)) / f.EraseBlockSize() - - unlockFlash() - defer lockFlash() - - for i := blk; i < blk+len; i++ { - if err := eraseBlock(uint32(i)); err != nil { - return err - } - } - - return nil -} - -const memoryStart = 0x08000000 - -func unlockFlash() { - // keys as described rm0461 page 76 - var fkey1 uint32 = 0x45670123 - var fkey2 uint32 = 0xCDEF89AB - - // Wait for the flash memory not to be busy - for stm32.FLASH.GetSR_BSY() != 0 { - } - - // Check if the controller is unlocked already - if stm32.FLASH.GetCR_LOCK() != 0 { - // Write the first key - stm32.FLASH.SetKEYR(fkey1) - // Write the second key - stm32.FLASH.SetKEYR(fkey2) - } -} - -func lockFlash() { - stm32.FLASH.SetCR_LOCK(1) -} diff --git a/emb/machine/machine_stm32_gpio_reva.go b/emb/machine/machine_stm32_gpio_reva.go deleted file mode 100644 index 2fb5a03..0000000 --- a/emb/machine/machine_stm32_gpio_reva.go +++ /dev/null @@ -1,92 +0,0 @@ -//go:build stm32 && !stm32l4 && !stm32l5 && !stm32wlx - -package machine - -import ( - "device/stm32" -) - -// This variant of the GPIO input interrupt logic is for -// chips with a smaller number of interrupt channels -// (that fits in a single register). - -// -// STM32 allows one interrupt source per pin number, with -// the same pin number in different ports sharing a single -// interrupt source (so PA0, PB0, PC0 all share). Only a -// single physical pin can be connected to each interrupt -// line. -// -// To call interrupt callbacks, we record here for each -// pin number the callback and the actual associated pin. -// - -// Callbacks for pin interrupt events -var pinCallbacks [16]func(Pin) - -// The pin currently associated with interrupt callback -// for a given slot. -var interruptPins [16]Pin - -// SetInterrupt sets an interrupt to be executed when a particular pin changes -// state. The pin should already be configured as an input, including a pull up -// or down if no external pull is provided. -// -// This call will replace a previously set callback on this pin. You can pass a -// nil func to unset the pin change interrupt. If you do so, the change -// parameter is ignored and can be set to any value (such as 0). -func (p Pin) SetInterrupt(change PinChange, callback func(Pin)) error { - port := uint32(uint8(p) / 16) - pin := uint8(p) % 16 - - enableEXTIConfigRegisters() - - if callback == nil { - stm32.EXTI.IMR.ClearBits(1 << pin) - pinCallbacks[pin] = nil - return nil - } - - if pinCallbacks[pin] != nil { - // The pin was already configured. - // To properly re-configure a pin, unset it first and set a new - // configuration. - return ErrNoPinChangeChannel - } - - // Set the callback now (before the interrupt is enabled) to avoid - // possible race condition - pinCallbacks[pin] = callback - interruptPins[pin] = p - - crReg := getEXTIConfigRegister(pin) - shift := (pin & 0x3) * 4 - crReg.ReplaceBits(port, 0xf, shift) - - if (change & PinRising) != 0 { - stm32.EXTI.RTSR.SetBits(1 << pin) - } - if (change & PinFalling) != 0 { - stm32.EXTI.FTSR.SetBits(1 << pin) - } - stm32.EXTI.IMR.SetBits(1 << pin) - - intr := p.registerInterrupt() - intr.SetPriority(0) - intr.Enable() - - return nil -} - -func handlePinInterrupt(pin uint8) { - if stm32.EXTI.PR.HasBits(1 << pin) { - // Writing 1 to the pending register clears the - // pending flag for that bit - stm32.EXTI.PR.Set(1 << pin) - - callback := pinCallbacks[pin] - if callback != nil { - callback(interruptPins[pin]) - } - } -} diff --git a/emb/machine/machine_stm32_gpio_revb.go b/emb/machine/machine_stm32_gpio_revb.go deleted file mode 100644 index 49094c7..0000000 --- a/emb/machine/machine_stm32_gpio_revb.go +++ /dev/null @@ -1,79 +0,0 @@ -//go:build stm32l4 || stm32l5 - -package machine - -import ( - "device/stm32" -) - -// This variant of the GPIO input interrupt logic is for -// chips with a larger number of interrupt channels (more -// than fits in a single register). - -// -// STM32 allows one interrupt source per pin number, with -// the same pin number in different ports sharing a single -// interrupt source (so PA0, PB0, PC0 all share). Only a -// single physical pin can be connected to each interrupt -// line. -// -// To call interrupt callbacks, we record here for each -// pin number the callback and the actual associated pin. -// - -// Callbacks for pin interrupt events -var pinCallbacks [16]func(Pin) - -// The pin currently associated with interrupt callback -// for a given slot. -var interruptPins [16]Pin - -// SetInterrupt sets an interrupt to be executed when a particular pin changes -// state. The pin should already be configured as an input, including a pull up -// or down if no external pull is provided. -// -// This call will replace a previously set callback on this pin. You can pass a -// nil func to unset the pin change interrupt. If you do so, the change -// parameter is ignored and can be set to any value (such as 0). -func (p Pin) SetInterrupt(change PinChange, callback func(Pin)) error { - port := uint32(uint8(p) / 16) - pin := uint8(p) % 16 - - enableEXTIConfigRegisters() - - if callback == nil { - stm32.EXTI.IMR1.ClearBits(1 << pin) - pinCallbacks[pin] = nil - return nil - } - - if pinCallbacks[pin] != nil { - // The pin was already configured. - // To properly re-configure a pin, unset it first and set a new - // configuration. - return ErrNoPinChangeChannel - } - - // Set the callback now (before the interrupt is enabled) to avoid - // possible race condition - pinCallbacks[pin] = callback - interruptPins[pin] = p - - crReg := getEXTIConfigRegister(pin) - shift := (pin & 0x3) * 4 - crReg.ReplaceBits(port, 0xf, shift) - - if (change & PinRising) != 0 { - stm32.EXTI.RTSR1.SetBits(1 << pin) - } - if (change & PinFalling) != 0 { - stm32.EXTI.FTSR1.SetBits(1 << pin) - } - stm32.EXTI.IMR1.SetBits(1 << pin) - - intr := p.registerInterrupt() - intr.SetPriority(0) - intr.Enable() - - return nil -} diff --git a/emb/machine/machine_stm32_gpio_revb_mp.go b/emb/machine/machine_stm32_gpio_revb_mp.go deleted file mode 100644 index 2124b16..0000000 --- a/emb/machine/machine_stm32_gpio_revb_mp.go +++ /dev/null @@ -1,86 +0,0 @@ -//go:build stm32wlx - -package machine - -import ( - "device/stm32" -) - -// -// This variant of the GPIO input interrupt logic is for -// multi-core chips with a larger number of interrupt -// channels (more than fits in a single register). -// -// This logic is currently used by the single-core stm32wle5 -// due to a patch in stm32-rs project that has renamed the -// registers to match the dual-core names. This renaming is -// being discussed and may change in future. -// - -// -// STM32 allows one interrupt source per pin number, with -// the same pin number in different ports sharing a single -// interrupt source (so PA0, PB0, PC0 all share). Only a -// single physical pin can be connected to each interrupt -// line. -// -// To call interrupt callbacks, we record here for each -// pin number the callback and the actual associated pin. -// - -// Callbacks for pin interrupt events -var pinCallbacks [16]func(Pin) - -// The pin currently associated with interrupt callback -// for a given slot. -var interruptPins [16]Pin - -// SetInterrupt sets an interrupt to be executed when a particular pin changes -// state. The pin should already be configured as an input, including a pull up -// or down if no external pull is provided. -// -// This call will replace a previously set callback on this pin. You can pass a -// nil func to unset the pin change interrupt. If you do so, the change -// parameter is ignored and can be set to any value (such as 0). -func (p Pin) SetInterrupt(change PinChange, callback func(Pin)) error { - port := uint32(uint8(p) / 16) - pin := uint8(p) % 16 - - enableEXTIConfigRegisters() - - if callback == nil { - stm32.EXTI.C1IMR1.ClearBits(1 << pin) - pinCallbacks[pin] = nil - return nil - } - - if pinCallbacks[pin] != nil { - // The pin was already configured. - // To properly re-configure a pin, unset it first and set a new - // configuration. - return ErrNoPinChangeChannel - } - - // Set the callback now (before the interrupt is enabled) to avoid - // possible race condition - pinCallbacks[pin] = callback - interruptPins[pin] = p - - crReg := getEXTIConfigRegister(pin) - shift := (pin & 0x3) * 4 - crReg.ReplaceBits(port, 0xf, shift) - - if (change & PinRising) != 0 { - stm32.EXTI.RTSR1.SetBits(1 << pin) - } - if (change & PinFalling) != 0 { - stm32.EXTI.FTSR1.SetBits(1 << pin) - } - stm32.EXTI.C1IMR1.SetBits(1 << pin) - - intr := p.registerInterrupt() - intr.SetPriority(0) - intr.Enable() - - return nil -} diff --git a/emb/machine/machine_stm32_i2c_reva.go b/emb/machine/machine_stm32_i2c_reva.go deleted file mode 100644 index 1e4fd28..0000000 --- a/emb/machine/machine_stm32_i2c_reva.go +++ /dev/null @@ -1,436 +0,0 @@ -//go:build stm32f4 || stm32f1 - -package machine - -// I2C implementation for 'older' STM32 MCUs, including the F1 and F4 series -// of MCUs. - -import ( - "device/stm32" - "unsafe" -) - -const ( - flagOVR = 0x00010800 - flagAF = 0x00010400 - flagARLO = 0x00010200 - flagBERR = 0x00010100 - flagTXE = 0x00010080 - flagRXNE = 0x00010040 - flagSTOPF = 0x00010010 - flagADD10 = 0x00010008 - flagBTF = 0x00010004 - flagADDR = 0x00010002 - flagSB = 0x00010001 - flagDUALF = 0x00100080 - flagGENCALL = 0x00100010 - flagTRA = 0x00100004 - flagBUSY = 0x00100002 - flagMSL = 0x00100001 -) - -func (i2c *I2C) hasFlag(flag uint32) bool { - const mask = 0x0000FFFF - if uint8(flag>>16) == 1 { - return i2c.Bus.SR1.HasBits(flag & mask) - } else { - return i2c.Bus.SR2.HasBits(flag & mask) - } -} - -func (i2c *I2C) clearFlag(flag uint32) { - const mask = 0x0000FFFF - i2c.Bus.SR1.Set(^(flag & mask)) -} - -// clearFlagADDR reads both status registers to clear any pending ADDR flags. -func (i2c *I2C) clearFlagADDR() { - i2c.Bus.SR1.Get() - i2c.Bus.SR2.Get() -} - -func (i2c *I2C) waitForFlag(flag uint32, set bool) bool { - const tryMax = 10000 - hasFlag := false - for i := 0; !hasFlag && i < tryMax; i++ { - hasFlag = i2c.hasFlag(flag) == set - } - return hasFlag -} - -func (i2c *I2C) waitForFlagOrError(flag uint32, set bool) bool { - const tryMax = 10000 - hasFlag := false - for i := 0; !hasFlag && i < tryMax; i++ { - if hasFlag = i2c.hasFlag(flag) == set; !hasFlag { - // check for ACK failure - if i2c.hasFlag(flagAF) { - // generate stop condition - i2c.Bus.CR1.SetBits(stm32.I2C_CR1_STOP) - // clear pending flags - i2c.clearFlag(flagAF) - return false - } else if i2c.hasFlag(flagSTOPF) { - // clear stop flag - i2c.clearFlag(flagSTOPF) - return false - } - } - } - return hasFlag -} - -type transferOption uint32 - -const ( - frameFirst = 0x00000001 - frameFirstAndNext = 0x00000002 - frameNext = 0x00000004 - frameFirstAndLast = 0x00000008 - frameLastNoStop = 0x00000010 - frameLast = 0x00000020 - frameNoOption = 0xFFFF0000 -) - -// I2C fast mode (Fm) duty cycle -const ( - DutyCycle2 = 0 - DutyCycle16x9 = 1 -) - -// I2CConfig is used to store config info for I2C. -type I2CConfig struct { - Frequency uint32 - SCL Pin - SDA Pin - DutyCycle uint8 -} - -// Configure is intended to setup the STM32 I2C interface. -func (i2c *I2C) Configure(config I2CConfig) error { - - // The following is the required sequence in controller mode. - // 1. Program the peripheral input clock in I2C_CR2 Register in order to - // generate correct timings - // 2. Configure the clock control registers - // 3. Configure the rise time register - // 4. Program the I2C_CR1 register to enable the peripheral - // 5. Set the START bit in the I2C_CR1 register to generate a Start condition - - // disable I2C interface before any configuration changes - i2c.Bus.CR1.ClearBits(stm32.I2C_CR1_PE) - - // reset I2C bus - i2c.Bus.CR1.SetBits(stm32.I2C_CR1_SWRST) - i2c.Bus.CR1.ClearBits(stm32.I2C_CR1_SWRST) - - // enable clock for I2C - enableAltFuncClock(unsafe.Pointer(i2c.Bus)) - - // init pins - if config.SCL == 0 && config.SDA == 0 { - config.SCL = I2C0_SCL_PIN - config.SDA = I2C0_SDA_PIN - } - i2c.configurePins(config) - - // default to 100 kHz (Sm, standard mode) if no frequency is set - if config.Frequency == 0 { - config.Frequency = 100 * KHz - } - - // configure I2C input clock - i2c.Bus.CR2.SetBits(i2c.getFreqRange(config)) - - // configure rise time - i2c.Bus.TRISE.Set(i2c.getRiseTime(config)) - - // configure clock control - i2c.Bus.CCR.Set(i2c.getSpeed(config)) - - // disable GeneralCall and NoStretch modes - i2c.Bus.CR1.ClearBits(stm32.I2C_CR1_ENGC | stm32.I2C_CR1_NOSTRETCH) - - // enable I2C interface - i2c.Bus.CR1.SetBits(stm32.I2C_CR1_PE) - - return nil -} - -// SetBaudRate sets the communication speed for I2C. -func (i2c *I2C) SetBaudRate(br uint32) error { - // TODO: implement - return errI2CNotImplemented -} - -func (i2c *I2C) Tx(addr uint16, w, r []byte) error { - - if err := i2c.controllerTransmit(addr, w); nil != err { - return err - } - - if len(r) > 0 { - if err := i2c.controllerReceive(addr, r); nil != err { - return err - } - } - - return nil -} - -func (i2c *I2C) controllerTransmit(addr uint16, w []byte) error { - - if !i2c.waitForFlag(flagBUSY, false) { - return errI2CBusReadyTimeout - } - - // disable POS - i2c.Bus.CR1.ClearBits(stm32.I2C_CR1_POS) - - pos := 0 - rem := len(w) - - // send peripheral address - if err := i2c.controllerRequestWrite(addr, frameNoOption); nil != err { - return err - } - - // clear ADDR flag - i2c.clearFlagADDR() - - for rem > 0 { - // wait for TXE flag set - if !i2c.waitForFlagOrError(flagTXE, true) { - return errI2CAckExpected - } - - // write data to DR - i2c.Bus.DR.Set(uint32(w[pos])) - // update counters - pos++ - rem-- - - if i2c.hasFlag(flagBTF) && rem != 0 { - // write data to DR - i2c.Bus.DR.Set(uint32(w[pos])) - // update counters - pos++ - rem-- - } - - // wait for transfer finished flag BTF set - if !i2c.waitForFlagOrError(flagBTF, true) { - return errI2CWriteTimeout - } - } - - // generate stop condition - i2c.Bus.CR1.SetBits(stm32.I2C_CR1_STOP) - - return nil -} - -func (i2c *I2C) controllerRequestWrite(addr uint16, option transferOption) error { - - if frameFirstAndLast == option || frameFirst == option || frameNoOption == option { - // generate start condition - i2c.Bus.CR1.SetBits(stm32.I2C_CR1_START) - } else if false /* (hi2c->PreviousState == I2C_STATE_MASTER_BUSY_RX) */ { - // generate restart condition - i2c.Bus.CR1.SetBits(stm32.I2C_CR1_START) - } - - // ensure start bit is set - if !i2c.waitForFlag(flagSB, true) { - return errI2CSignalStartTimeout - } - - // send peripheral address - i2c.Bus.DR.Set(uint32(addr) << 1) - - // wait for address ACK from peripheral - if !i2c.waitForFlagOrError(flagADDR, true) { - return errI2CSignalStartTimeout - } - - return nil -} - -func (i2c *I2C) controllerReceive(addr uint16, r []byte) error { - - if !i2c.waitForFlag(flagBUSY, false) { - return errI2CBusReadyTimeout - } - - // disable POS - i2c.Bus.CR1.ClearBits(stm32.I2C_CR1_POS) - - pos := 0 - rem := len(r) - - // send peripheral address - if err := i2c.controllerRequestRead(addr, frameNoOption); nil != err { - return err - } - - switch rem { - case 0: - // clear ADDR flag - i2c.clearFlagADDR() - // generate stop condition - i2c.Bus.CR1.SetBits(stm32.I2C_CR1_STOP) - - case 1: - // disable ACK - i2c.Bus.CR1.ClearBits(stm32.I2C_CR1_ACK) - // clear ADDR flag - i2c.clearFlagADDR() - // generate stop condition - i2c.Bus.CR1.SetBits(stm32.I2C_CR1_STOP) - - case 2: - // disable ACK - i2c.Bus.CR1.ClearBits(stm32.I2C_CR1_ACK) - // enable POS - i2c.Bus.CR1.SetBits(stm32.I2C_CR1_POS) - // clear ADDR flag - i2c.clearFlagADDR() - - default: - // enable ACK - i2c.Bus.CR1.SetBits(stm32.I2C_CR1_ACK) - // clear ADDR flag - i2c.clearFlagADDR() - } - - for rem > 0 { - switch rem { - case 1: - // wait until RXNE flag is set - if !i2c.waitForFlagOrError(flagRXNE, true) { - return errI2CReadTimeout - } - - // read data from DR - r[pos] = byte(i2c.Bus.DR.Get()) - - // update counters - pos++ - rem-- - - case 2: - // wait until transfer finished flag BTF is set - if !i2c.waitForFlag(flagBTF, true) { - return errI2CReadTimeout - } - - // generate stop condition - i2c.Bus.CR1.SetBits(stm32.I2C_CR1_STOP) - - // read data from DR - r[pos] = byte(i2c.Bus.DR.Get()) - - // update counters - pos++ - rem-- - - // read data from DR - r[pos] = byte(i2c.Bus.DR.Get()) - - // update counters - pos++ - rem-- - - case 3: - // wait until transfer finished flag BTF is set - if !i2c.waitForFlag(flagBTF, true) { - return errI2CReadTimeout - } - - // disable ACK - i2c.Bus.CR1.ClearBits(stm32.I2C_CR1_ACK) - - // read data from DR - r[pos] = byte(i2c.Bus.DR.Get()) - - // update counters - pos++ - rem-- - - // wait until transfer finished flag BTF is set - if !i2c.waitForFlag(flagBTF, true) { - return errI2CReadTimeout - } - - // generate stop condition - i2c.Bus.CR1.SetBits(stm32.I2C_CR1_STOP) - - // read data from DR - r[pos] = byte(i2c.Bus.DR.Get()) - - // update counters - pos++ - rem-- - - // read data from DR - r[pos] = byte(i2c.Bus.DR.Get()) - - // update counters - pos++ - rem-- - - default: - // wait until RXNE flag is set - if !i2c.waitForFlagOrError(flagRXNE, true) { - return errI2CReadTimeout - } - - // read data from DR - r[pos] = byte(i2c.Bus.DR.Get()) - - // update counters - pos++ - rem-- - - if i2c.hasFlag(flagBTF) { - // read data from DR - r[pos] = byte(i2c.Bus.DR.Get()) - - // update counters - pos++ - rem-- - } - } - } - - return nil -} - -func (i2c *I2C) controllerRequestRead(addr uint16, option transferOption) error { - - // enable ACK - i2c.Bus.CR1.SetBits(stm32.I2C_CR1_ACK) - - if frameFirstAndLast == option || frameFirst == option || frameNoOption == option { - // generate start condition - i2c.Bus.CR1.SetBits(stm32.I2C_CR1_START) - } else if false /* (hi2c->PreviousState == I2C_STATE_MASTER_BUSY_TX) */ { - // generate restart condition - i2c.Bus.CR1.SetBits(stm32.I2C_CR1_START) - } - - // ensure start bit is set - if !i2c.waitForFlag(flagSB, true) { - return errI2CSignalStartTimeout - } - - // send peripheral address - i2c.Bus.DR.Set(uint32(addr)<<1 | 1) - - // wait for address ACK from peripheral - if !i2c.waitForFlagOrError(flagADDR, true) { - return errI2CSignalStartTimeout - } - - return nil -} diff --git a/emb/machine/machine_stm32_i2c_revb.go b/emb/machine/machine_stm32_i2c_revb.go deleted file mode 100644 index 006661f..0000000 --- a/emb/machine/machine_stm32_i2c_revb.go +++ /dev/null @@ -1,378 +0,0 @@ -//go:build stm32l5 || stm32f7 || stm32l4 || stm32l0 || stm32wlx - -package machine - -import ( - "device/stm32" - "unsafe" -) - -//go:linkname ticks runtime.ticks -func ticks() int64 - -// I2C implementation for 'newer' STM32 MCUs, including the F7, L5 and L4 -// series of MCUs. -// -// Currently, only 100KHz mode is supported - -const ( - flagBUSY = stm32.I2C_ISR_BUSY - flagTCR = stm32.I2C_ISR_TCR - flagRXNE = stm32.I2C_ISR_RXNE - flagSTOPF = stm32.I2C_ISR_STOPF - flagAF = stm32.I2C_ISR_NACKF - flagTXIS = stm32.I2C_ISR_TXIS - flagTXE = stm32.I2C_ISR_TXE -) - -const ( - MAX_NBYTE_SIZE = 255 - - // 100ms delay = 100e6ns / 16ns - // In runtime_stm32_timers.go, tick is fixed at 16ns per tick - TIMEOUT_TICKS = 100e6 / 16 - - I2C_NO_STARTSTOP = 0x0 - I2C_GENERATE_START_WRITE = 0x80000000 | stm32.I2C_CR2_START - I2C_GENERATE_START_READ = 0x80000000 | stm32.I2C_CR2_START | stm32.I2C_CR2_RD_WRN - I2C_GENERATE_STOP = 0x80000000 | stm32.I2C_CR2_STOP -) - -type I2C struct { - Bus *stm32.I2C_Type - AltFuncSelector uint8 -} - -// I2CConfig is used to store config info for I2C. -type I2CConfig struct { - Frequency uint32 - SCL Pin - SDA Pin -} - -func (i2c *I2C) Configure(config I2CConfig) error { - // Frequency range - switch config.Frequency { - case 0: - config.Frequency = 100 * KHz - case 10 * KHz, 100 * KHz, 400 * KHz, 500 * KHz: - default: - return errI2CNotImplemented - } - - // disable I2C interface before any configuration changes - i2c.Bus.CR1.ClearBits(stm32.I2C_CR1_PE) - - // enable clock for I2C - enableAltFuncClock(unsafe.Pointer(i2c.Bus)) - - // init pins - if config.SCL == 0 && config.SDA == 0 { - config.SCL = I2C0_SCL_PIN - config.SDA = I2C0_SDA_PIN - } - i2c.configurePins(config) - - i2c.Bus.TIMINGR.Set(i2c.getFreqRange(config.Frequency)) - - // Disable Own Address1 before set the Own Address1 configuration - i2c.Bus.OAR1.ClearBits(stm32.I2C_OAR1_OA1EN) - - // 7 bit addressing, no self address - i2c.Bus.OAR1.Set(stm32.I2C_OAR1_OA1EN) - - // Enable the AUTOEND by default, and enable NACK (should be disable only during Slave process - i2c.Bus.CR2.Set(stm32.I2C_CR2_AUTOEND | stm32.I2C_CR2_NACK) - - // Disable Own Address2 / Dual Addressing - i2c.Bus.OAR2.Set(0) - - // Disable Generalcall and NoStretch, Enable peripheral - i2c.Bus.CR1.Set(stm32.I2C_CR1_PE) - - return nil -} - -// SetBaudRate sets the communication speed for I2C. -func (i2c *I2C) SetBaudRate(br uint32) error { - switch br { - case 10 * KHz, 100 * KHz, 400 * KHz, 500 * KHz: - default: - return errI2CNotImplemented - } - - // disable I2C interface before any configuration changes - i2c.Bus.CR1.ClearBits(stm32.I2C_CR1_PE) - - i2c.Bus.TIMINGR.Set(i2c.getFreqRange(br)) - - // Disable Generalcall and NoStretch, Enable peripheral - i2c.Bus.CR1.Set(stm32.I2C_CR1_PE) - - return nil -} - -func (i2c *I2C) Tx(addr uint16, w, r []byte) error { - if len(w) > 0 { - if err := i2c.controllerTransmit(addr, w); nil != err { - return err - } - } - - if len(r) > 0 { - if err := i2c.controllerReceive(addr, r); nil != err { - return err - } - } - - return nil -} - -func (i2c *I2C) configurePins(config I2CConfig) { - config.SCL.ConfigureAltFunc(PinConfig{Mode: PinModeI2CSCL}, i2c.AltFuncSelector) - config.SDA.ConfigureAltFunc(PinConfig{Mode: PinModeI2CSDA}, i2c.AltFuncSelector) -} - -func (i2c *I2C) controllerTransmit(addr uint16, w []byte) error { - start := ticks() - - if !i2c.waitOnFlagUntilTimeout(flagBUSY, false, start) { - return errI2CBusReadyTimeout - } - - pos := 0 - xferCount := len(w) - xferSize := uint8(xferCount) - if xferCount > MAX_NBYTE_SIZE { - // Large write, indicate reload - xferSize = MAX_NBYTE_SIZE - i2c.transferConfig(addr, xferSize, stm32.I2C_CR2_RELOAD, I2C_GENERATE_START_WRITE) - } else { - // Small write, auto-end - i2c.transferConfig(addr, xferSize, stm32.I2C_CR2_AUTOEND, I2C_GENERATE_START_WRITE) - } - - for xferCount > 0 { - if !i2c.waitOnTXISFlagUntilTimeout(start) { - return errI2CWriteTimeout - } - - i2c.Bus.TXDR.Set(uint32(w[pos])) - pos++ - xferCount-- - xferSize-- - - // If we've written the last byte of this chunk - if xferCount != 0 && xferSize == 0 { - // Wait for Transfer Complete Reload to be flagged - if !i2c.waitOnFlagUntilTimeout(flagTCR, true, start) { - return errI2CWriteTimeout - } - - if xferCount > MAX_NBYTE_SIZE { - // Large write remaining, indicate reload - xferSize = MAX_NBYTE_SIZE - i2c.transferConfig(addr, xferSize, stm32.I2C_CR2_RELOAD, I2C_NO_STARTSTOP) - } else { - // Small write, auto-end - xferSize = uint8(xferCount) - i2c.transferConfig(addr, xferSize, stm32.I2C_CR2_AUTOEND, I2C_NO_STARTSTOP) - } - } - } - - if !i2c.waitOnStopFlagUntilTimeout(start) { - return errI2CWriteTimeout - } - - i2c.clearFlag(stm32.I2C_ISR_STOPF) - - i2c.resetCR2() - - return nil -} - -func (i2c *I2C) controllerReceive(addr uint16, r []byte) error { - start := ticks() - - if !i2c.waitOnFlagUntilTimeout(flagBUSY, false, start) { - return errI2CBusReadyTimeout - } - - pos := 0 - xferCount := len(r) - xferSize := uint8(xferCount) - if xferCount > MAX_NBYTE_SIZE { - // Large read, indicate reload - xferSize = MAX_NBYTE_SIZE - i2c.transferConfig(addr, xferSize, stm32.I2C_CR2_RELOAD, I2C_GENERATE_START_READ) - } else { - // Small read, auto-end - i2c.transferConfig(addr, xferSize, stm32.I2C_CR2_AUTOEND, I2C_GENERATE_START_READ) - } - - for xferCount > 0 { - if !i2c.waitOnRXNEFlagUntilTimeout(start) { - return errI2CWriteTimeout - } - - r[pos] = uint8(i2c.Bus.RXDR.Get()) - pos++ - xferCount-- - xferSize-- - - // If we've read the last byte of this chunk - if xferCount != 0 && xferSize == 0 { - // Wait for Transfer Complete Reload to be flagged - if !i2c.waitOnFlagUntilTimeout(flagTCR, true, start) { - return errI2CWriteTimeout - } - - if xferCount > MAX_NBYTE_SIZE { - // Large read remaining, indicate reload - xferSize = MAX_NBYTE_SIZE - i2c.transferConfig(addr, xferSize, stm32.I2C_CR2_RELOAD, I2C_NO_STARTSTOP) - } else { - // Small read, auto-end - xferSize = uint8(xferCount) - i2c.transferConfig(addr, xferSize, stm32.I2C_CR2_AUTOEND, I2C_NO_STARTSTOP) - } - } - } - - if !i2c.waitOnStopFlagUntilTimeout(start) { - return errI2CWriteTimeout - } - - i2c.clearFlag(stm32.I2C_ISR_STOPF) - - i2c.resetCR2() - - return nil -} - -func (i2c *I2C) waitOnFlagUntilTimeout(flag uint32, set bool, startTicks int64) bool { - for i2c.hasFlag(flag) != set { - if (ticks() - startTicks) > TIMEOUT_TICKS { - return false - } - } - return true -} - -func (i2c *I2C) waitOnRXNEFlagUntilTimeout(startTicks int64) bool { - for !i2c.hasFlag(flagRXNE) { - if i2c.isAcknowledgeFailed(startTicks) { - return false - } - - if i2c.hasFlag(flagSTOPF) { - i2c.clearFlag(flagSTOPF) - i2c.resetCR2() - return false - } - - if (ticks() - startTicks) > TIMEOUT_TICKS { - return false - } - } - - return true -} - -func (i2c *I2C) waitOnTXISFlagUntilTimeout(startTicks int64) bool { - for !i2c.hasFlag(flagTXIS) { - if i2c.isAcknowledgeFailed(startTicks) { - return false - } - - if (ticks() - startTicks) > TIMEOUT_TICKS { - return false - } - } - - return true -} - -func (i2c *I2C) waitOnStopFlagUntilTimeout(startTicks int64) bool { - for !i2c.hasFlag(flagSTOPF) { - if i2c.isAcknowledgeFailed(startTicks) { - return false - } - - if (ticks() - startTicks) > TIMEOUT_TICKS { - return false - } - } - - return true -} - -func (i2c *I2C) isAcknowledgeFailed(startTicks int64) bool { - if i2c.hasFlag(flagAF) { - // Wait until STOP Flag is reset - // AutoEnd should be initiate after AF - for !i2c.hasFlag(flagSTOPF) { - if (ticks() - startTicks) > TIMEOUT_TICKS { - return true - } - } - - i2c.clearFlag(flagAF) - i2c.clearFlag(flagSTOPF) - i2c.flushTXDR() - i2c.resetCR2() - - return true - } - - return false -} - -func (i2c *I2C) flushTXDR() { - // If a pending TXIS flag is set, write a dummy data in TXDR to clear it - if i2c.hasFlag(flagTXIS) { - i2c.Bus.TXDR.Set(0) - } - - // Flush TX register if not empty - if !i2c.hasFlag(flagTXE) { - i2c.clearFlag(flagTXE) - } -} - -func (i2c *I2C) resetCR2() { - i2c.Bus.CR2.ClearBits(stm32.I2C_CR2_SADD_Msk | - stm32.I2C_CR2_HEAD10R_Msk | - stm32.I2C_CR2_NBYTES_Msk | - stm32.I2C_CR2_RELOAD_Msk | - stm32.I2C_CR2_RD_WRN_Msk) -} - -func (i2c *I2C) transferConfig(addr uint16, size uint8, mode uint32, request uint32) { - mask := uint32(stm32.I2C_CR2_SADD_Msk | - stm32.I2C_CR2_NBYTES_Msk | - stm32.I2C_CR2_RELOAD_Msk | - stm32.I2C_CR2_AUTOEND_Msk | - (stm32.I2C_CR2_RD_WRN & uint32(request>>(31-stm32.I2C_CR2_RD_WRN_Pos))) | - stm32.I2C_CR2_START_Msk | - stm32.I2C_CR2_STOP_Msk) - - value := (uint32(addr<<1) & stm32.I2C_CR2_SADD_Msk) | - ((uint32(size) << stm32.I2C_CR2_NBYTES_Pos) & stm32.I2C_CR2_NBYTES_Msk) | - mode | request - - i2c.Bus.CR2.ReplaceBits(value, mask, 0) -} - -func (i2c *I2C) hasFlag(flag uint32) bool { - return i2c.Bus.ISR.HasBits(flag) -} - -func (i2c *I2C) clearFlag(flag uint32) { - if flag == stm32.I2C_ISR_TXE { - i2c.Bus.ISR.SetBits(flag) - } else { - i2c.Bus.ICR.SetBits(flag) - } -} diff --git a/emb/machine/machine_stm32_iwdg.go b/emb/machine/machine_stm32_iwdg.go deleted file mode 100644 index 1139d54..0000000 --- a/emb/machine/machine_stm32_iwdg.go +++ /dev/null @@ -1,66 +0,0 @@ -//go:build stm32 - -package machine - -import "device/stm32" - -var ( - Watchdog = &watchdogImpl{} -) - -const ( - // WatchdogMaxTimeout in milliseconds (32.768s) - // - // Timeout is based on 12-bit counter with /256 divider on - // 32.768kHz clock. See 21.3.3 of RM0090 for table. - WatchdogMaxTimeout = ((0xfff + 1) * 256 * 1024) / 32768 -) - -const ( - // Enable access to PR, RLR and WINR registers (0x5555) - iwdgKeyEnable = 0x5555 - // Reset the watchdog value (0xAAAA) - iwdgKeyReset = 0xaaaa - // Start the watchdog (0xCCCC) - iwdgKeyStart = 0xcccc - // Divide by 256 - iwdgDiv256 = 6 -) - -type watchdogImpl struct { -} - -// Configure the watchdog. -// -// This method should not be called after the watchdog is started and on -// some platforms attempting to reconfigure after starting the watchdog -// is explicitly forbidden / will not work. -func (wd *watchdogImpl) Configure(config WatchdogConfig) error { - - // Enable configuration of IWDG - stm32.IWDG.KR.Set(iwdgKeyEnable) - - // Unconditionally divide by /256 since we don't really need accuracy - // less than 8ms - stm32.IWDG.PR.Set(iwdgDiv256) - - timeout := config.TimeoutMillis - if timeout > WatchdogMaxTimeout { - timeout = WatchdogMaxTimeout - } - - // Set reload value based on /256 divider - stm32.IWDG.RLR.Set(((config.TimeoutMillis*32768 + (256 * 1024) - 1) / (256 * 1024)) - 1) - return nil -} - -// Starts the watchdog. -func (wd *watchdogImpl) Start() error { - stm32.IWDG.KR.Set(iwdgKeyStart) - return nil -} - -// Update the watchdog, indicating that `source` is healthy. -func (wd *watchdogImpl) Update() { - stm32.IWDG.KR.Set(iwdgKeyReset) -} diff --git a/emb/machine/machine_stm32_moder_gpio.go b/emb/machine/machine_stm32_moder_gpio.go deleted file mode 100644 index b8585c2..0000000 --- a/emb/machine/machine_stm32_moder_gpio.go +++ /dev/null @@ -1,164 +0,0 @@ -//go:build stm32 && !stm32f103 - -package machine - -import ( - "device/stm32" -) - -// GPIO for the stm32 families except the stm32f1xx which uses a simpler but -// less flexible mechanism. Extend the go:build directive above to exclude other -// models in the stm32f1xx series as necessary - -const ( - // Mode Flag - PinOutput PinMode = 0 - PinInput PinMode = PinInputFloating - PinInputFloating PinMode = 1 - PinInputPulldown PinMode = 2 - PinInputPullup PinMode = 3 - - // for UART - PinModeUARTTX PinMode = 4 - PinModeUARTRX PinMode = 5 - - // for I2C - PinModeI2CSCL PinMode = 6 - PinModeI2CSDA PinMode = 7 - - // for SPI - PinModeSPICLK PinMode = 8 - PinModeSPISDO PinMode = 9 - PinModeSPISDI PinMode = 10 - - // for analog/ADC - PinInputAnalog PinMode = 11 - - // for PWM - PinModePWMOutput PinMode = 12 -) - -// Define several bitfields that have different names across chip families but -// essentially have the same meaning. -const ( - // MODER bitfields. - gpioModeInput = 0 - gpioModeOutput = 1 - gpioModeAlternate = 2 - gpioModeAnalog = 3 - gpioModeMask = 0x3 - - // PUPDR bitfields. - gpioPullFloating = 0 - gpioPullUp = 1 - gpioPullDown = 2 - gpioPullMask = 0x3 - - // OSPEED bitfields. - gpioOutputSpeedVeryHigh = 3 - gpioOutputSpeedHigh = 2 - gpioOutputSpeedMedium = 1 - gpioOutputSpeedLow = 0 - gpioOutputSpeedMask = 0x3 -) - -// Configure this pin with the given configuration -func (p Pin) Configure(config PinConfig) { - // Use the default system alternate function; this - // will only be used if you try to call this with - // one of the peripheral modes instead of vanilla GPIO. - p.ConfigureAltFunc(config, 0) -} - -// Configure this pin with the given configuration including alternate -// -// function mapping if necessary. -func (p Pin) ConfigureAltFunc(config PinConfig, altFunc uint8) { - // Configure the GPIO pin. - p.enableClock() - port := p.getPort() - pos := (uint8(p) % 16) * 2 // assume each field is two bits in size (with mask 0x3) - - switch config.Mode { - - // GPIO - case PinInputFloating: - port.MODER.ReplaceBits(gpioModeInput, gpioModeMask, pos) - port.PUPDR.ReplaceBits(gpioPullFloating, gpioPullMask, pos) - case PinInputPulldown: - port.MODER.ReplaceBits(gpioModeInput, gpioModeMask, pos) - port.PUPDR.ReplaceBits(gpioPullDown, gpioPullMask, pos) - case PinInputPullup: - port.MODER.ReplaceBits(gpioModeInput, gpioModeMask, pos) - port.PUPDR.ReplaceBits(gpioPullUp, gpioPullMask, pos) - case PinOutput: - port.MODER.ReplaceBits(gpioModeOutput, gpioModeMask, pos) - port.OSPEEDR.ReplaceBits(gpioOutputSpeedHigh, gpioOutputSpeedMask, pos) - - // UART - case PinModeUARTTX: - port.MODER.ReplaceBits(gpioModeAlternate, gpioModeMask, pos) - port.OSPEEDR.ReplaceBits(gpioOutputSpeedHigh, gpioOutputSpeedMask, pos) - port.PUPDR.ReplaceBits(gpioPullUp, gpioPullMask, pos) - p.SetAltFunc(altFunc) - case PinModeUARTRX: - port.MODER.ReplaceBits(gpioModeAlternate, gpioModeMask, pos) - port.PUPDR.ReplaceBits(gpioPullFloating, gpioPullMask, pos) - p.SetAltFunc(altFunc) - - // I2C - case PinModeI2CSCL: - port.MODER.ReplaceBits(gpioModeAlternate, gpioModeMask, pos) - port.OTYPER.ReplaceBits(stm32.GPIO_OTYPER_OT0_OpenDrain, stm32.GPIO_OTYPER_OT0_Msk, pos/2) - port.OSPEEDR.ReplaceBits(gpioOutputSpeedLow, gpioOutputSpeedMask, pos) - port.PUPDR.ReplaceBits(gpioPullUp, gpioPullMask, pos) - p.SetAltFunc(altFunc) - case PinModeI2CSDA: - port.MODER.ReplaceBits(gpioModeAlternate, gpioModeMask, pos) - port.OTYPER.ReplaceBits(stm32.GPIO_OTYPER_OT0_OpenDrain, stm32.GPIO_OTYPER_OT0_Msk, pos/2) - port.OSPEEDR.ReplaceBits(gpioOutputSpeedLow, gpioOutputSpeedMask, pos) - port.PUPDR.ReplaceBits(gpioPullUp, gpioPullMask, pos) - p.SetAltFunc(altFunc) - - // SPI - case PinModeSPICLK: - port.MODER.ReplaceBits(gpioModeAlternate, gpioModeMask, pos) - port.OSPEEDR.ReplaceBits(gpioOutputSpeedHigh, gpioOutputSpeedMask, pos) - port.PUPDR.ReplaceBits(gpioPullFloating, gpioPullMask, pos) - p.SetAltFunc(altFunc) - case PinModeSPISDO: - port.MODER.ReplaceBits(gpioModeAlternate, gpioModeMask, pos) - port.OSPEEDR.ReplaceBits(gpioOutputSpeedLow, gpioOutputSpeedMask, pos) - port.PUPDR.ReplaceBits(gpioPullFloating, gpioPullMask, pos) - p.SetAltFunc(altFunc) - case PinModeSPISDI: - port.MODER.ReplaceBits(gpioModeAlternate, gpioModeMask, pos) - port.OSPEEDR.ReplaceBits(gpioOutputSpeedLow, gpioOutputSpeedMask, pos) - port.PUPDR.ReplaceBits(gpioPullFloating, gpioPullMask, pos) - p.SetAltFunc(altFunc) - - // PWM - case PinModePWMOutput: - port.MODER.ReplaceBits(gpioModeAlternate, gpioModeMask, pos) - port.OSPEEDR.ReplaceBits(gpioOutputSpeedHigh, gpioOutputSpeedMask, pos) - port.PUPDR.ReplaceBits(gpioPullFloating, gpioPullMask, pos) - p.SetAltFunc(altFunc) - - // ADC - case PinInputAnalog: - port.MODER.ReplaceBits(gpioModeAnalog, gpioModeMask, pos) - port.PUPDR.ReplaceBits(gpioPullFloating, gpioPullMask, pos) - } -} - -// SetAltFunc maps the given alternative function to the I/O pin -func (p Pin) SetAltFunc(af uint8) { - port := p.getPort() - pin := uint8(p) % 16 - pos := (pin % 8) * 4 - if pin < 8 { - port.AFRL.ReplaceBits(uint32(af), 0xf, pos) - } else { - port.AFRH.ReplaceBits(uint32(af), 0xf, pos) - } -} diff --git a/emb/machine/machine_stm32_rng.go b/emb/machine/machine_stm32_rng.go deleted file mode 100644 index 5eaff96..0000000 --- a/emb/machine/machine_stm32_rng.go +++ /dev/null @@ -1,35 +0,0 @@ -//go:build stm32 && !(stm32f103 || stm32l0x1) - -package machine - -import "device/stm32" - -var rngInitDone = false - -const RNG_MAX_READ_RETRIES = 1000 - -// GetRNG returns 32 bits of cryptographically secure random data -func GetRNG() (uint32, error) { - if !rngInitDone { - initRNG() - rngInitDone = true - } - - if stm32.RNG.SR.HasBits(stm32.RNG_SR_CECS) { - return 0, ErrClockRNG - } - if stm32.RNG.SR.HasBits(stm32.RNG_SR_SECS) { - return 0, ErrSeedRNG - } - - cnt := RNG_MAX_READ_RETRIES - for !stm32.RNG.SR.HasBits(stm32.RNG_SR_DRDY) { - cnt-- - if cnt == 0 { - return 0, ErrTimeoutRNG - } - } - - ret := stm32.RNG.DR.Get() - return ret, nil -} diff --git a/emb/machine/machine_stm32_spi.go b/emb/machine/machine_stm32_spi.go deleted file mode 100644 index 3c6e0b6..0000000 --- a/emb/machine/machine_stm32_spi.go +++ /dev/null @@ -1,147 +0,0 @@ -//go:build stm32 && !stm32f7x2 && !stm32l5x2 - -package machine - -// Peripheral abstraction layer for SPI on the stm32 family - -import ( - "device/stm32" - "runtime/volatile" - "unsafe" -) - -// SPIConfig is used to store config info for SPI. -type SPIConfig struct { - Frequency uint32 - SCK Pin - SDO Pin - SDI Pin - LSBFirst bool - Mode uint8 -} - -// Configure is intended to setup the STM32 SPI1 interface. -func (spi *SPI) Configure(config SPIConfig) error { - - // -- CONFIGURING THE SPI IN MASTER MODE -- - // - // 1. Select the BR[2:0] bits to define the serial clock baud rate (see - // SPI_CR1 register). - // 2. Select the CPOL and CPHA bits to define one of the four relationships - // between the data transfer and the serial clock (see Figure 248). This - // step is not required when the TI mode is selected. - // 3. Set the DFF bit to define 8- or 16-bit data frame format - // 4. Configure the LSBFIRST bit in the SPI_CR1 register to define the frame - // format. This step is not required when the TI mode is selected. - // 5. If the NSS pin is required in input mode, in hardware mode, connect the - // NSS pin to a high-level signal during the complete byte transmit - // sequence. In NSS software mode, set the SSM and SSI bits in the SPI_CR1 - // register. If the NSS pin is required in output mode, the SSOE bit only - // should be set. This step is not required when the TI mode is selected. - // 6. Set the FRF bit in SPI_CR2 to select the TI protocol for serial - // communications. - // 7. The MSTR and SPE bits must be set (they remain set only if the NSS pin - // is connected to a high-level signal). - - // disable SPI interface before any configuration changes - spi.Bus.CR1.ClearBits(stm32.SPI_CR1_SPE) - - // enable clock for SPI - enableAltFuncClock(unsafe.Pointer(spi.Bus)) - - // init pins - if config.SCK == 0 && config.SDO == 0 && config.SDI == 0 { - config.SCK = SPI0_SCK_PIN - config.SDO = SPI0_SDO_PIN - config.SDI = SPI0_SDI_PIN - } - spi.configurePins(config) - - // Get SPI baud rate based on the bus speed it's attached to - var conf uint32 = spi.getBaudRate(config) - - // set bit transfer order - if config.LSBFirst { - conf |= stm32.SPI_CR1_LSBFIRST - } - - // set polarity and phase on the SPI interface - switch config.Mode { - case Mode1: - conf |= stm32.SPI_CR1_CPHA - case Mode2: - conf |= stm32.SPI_CR1_CPOL - case Mode3: - conf |= stm32.SPI_CR1_CPOL - conf |= stm32.SPI_CR1_CPHA - } - - // configure as SPI master - conf |= stm32.SPI_CR1_MSTR | stm32.SPI_CR1_SSI - - // enable the SPI interface - conf |= stm32.SPI_CR1_SPE - - // use software CS (GPIO) by default - conf |= stm32.SPI_CR1_SSM - - // now set the configuration - spi.Bus.CR1.Set(conf) - - // Series-specific configuration to set 8-bit transfer mode - spi.config8Bits() - - // enable SPI - spi.Bus.CR1.SetBits(stm32.SPI_CR1_SPE) - - return nil -} - -// Transfer writes/reads a single byte using the SPI interface. -func (spi *SPI) Transfer(w byte) (byte, error) { - - // 1. Enable the SPI by setting the SPE bit to 1. - // 2. Write the first data item to be transmitted into the SPI_DR register - // (this clears the TXE flag). - // 3. Wait until TXE=1 and write the second data item to be transmitted. Then - // wait until RXNE=1 and read the SPI_DR to get the first received data - // item (this clears the RXNE bit). Repeat this operation for each data - // item to be transmitted/received until the n–1 received data. - // 4. Wait until RXNE=1 and read the last received data. - // 5. Wait until TXE=1 and then wait until BSY=0 before disabling the SPI. - - // put output word (8-bit) in data register (DR), which is parallel-loaded - // into shift register, and shifted out on MOSI. Some series have 16-bit - // register but writes must be strictly 8-bit to output a byte. Writing - // 16-bits indicates a packed transfer (2 bytes). - (*volatile.Register8)(unsafe.Pointer(&spi.Bus.DR.Reg)).Set(w) - - // wait for SPI bus receive buffer not empty bit (RXNE) to be set. - // warning: blocks forever until this condition is met. - for !spi.Bus.SR.HasBits(stm32.SPI_SR_RXNE) { - } - - // copy input word (8-bit) in data register (DR), which was shifted in on MISO - // and parallel-loaded into register. - data := byte(spi.Bus.DR.Get()) - - // wait for SPI bus transmit buffer empty bit (TXE) to be set. - // warning: blocks forever until this condition is met. - for !spi.Bus.SR.HasBits(stm32.SPI_SR_TXE) { - } - - // wait for SPI bus busy bit (BSY) to be clear to indicate synchronous - // transfer complete. this will effectively prevent this Transfer() function - // from being capable of maintaining high-bandwidth communication throughput, - // but it will help guarantee stability on the bus. - for spi.Bus.SR.HasBits(stm32.SPI_SR_BSY) { - } - - // clear the overrun flag (only in full-duplex mode) - if !spi.Bus.CR1.HasBits(stm32.SPI_CR1_RXONLY | stm32.SPI_CR1_BIDIMODE | stm32.SPI_CR1_BIDIOE) { - spi.Bus.SR.Get() - } - - // Return received data from SPI data register - return data, nil -} diff --git a/emb/machine/machine_stm32_tim.go b/emb/machine/machine_stm32_tim.go deleted file mode 100644 index 4898ed9..0000000 --- a/emb/machine/machine_stm32_tim.go +++ /dev/null @@ -1,340 +0,0 @@ -//go:build stm32 - -package machine - -// The type alias `arrtype` should be defined to either uint32 or uint16 -// depending on the size of that register in the MCU's TIM_Type structure. - -import ( - "device/stm32" - "runtime/interrupt" - "runtime/volatile" -) - -const PWM_MODE1 = 0x6 - -type TimerCallback func() -type ChannelCallback func(channel uint8) - -type PinFunction struct { - Pin Pin - AltFunc uint8 -} - -type TimerChannel struct { - Pins []PinFunction -} - -type TIM struct { - EnableRegister *volatile.Register32 - EnableFlag uint32 - Device *stm32.TIM_Type - Channels [4]TimerChannel - UpInterrupt interrupt.Interrupt - OCInterrupt interrupt.Interrupt - - wraparoundCallback TimerCallback - channelCallbacks [4]ChannelCallback - - busFreq uint64 -} - -// Configure enables and configures this PWM. -func (t *TIM) Configure(config PWMConfig) error { - // Enable device - t.EnableRegister.SetBits(t.EnableFlag) - - err := t.setPeriod(config.Period, true) - if err != nil { - return err - } - - // Auto-repeat - t.Device.EGR.SetBits(stm32.TIM_EGR_UG) - - // Enable the timer - t.Device.CR1.SetBits(stm32.TIM_CR1_CEN | stm32.TIM_CR1_ARPE) - - return nil -} - -func (t *TIM) Count() uint32 { - return uint32(t.Device.CNT.Get()) -} - -// SetWraparoundInterrupt configures a callback to be called each -// time the timer 'wraps-around'. -// -// For example, if `Configure(PWMConfig{Period:1000000})` is used, -// to set the timer period to 1ms, this callback will be called every -// 1ms. -func (t *TIM) SetWraparoundInterrupt(callback TimerCallback) error { - // Disable this interrupt to prevent race conditions - //t.UpInterrupt.Disable() - - // Ensure the interrupt handler for Update events is registered - t.UpInterrupt = t.registerUPInterrupt() - - // Clear update flag - t.Device.SR.ClearBits(stm32.TIM_SR_UIF) - - t.wraparoundCallback = callback - t.UpInterrupt.SetPriority(0xc1) - t.UpInterrupt.Enable() - - // Enable the hardware interrupt - t.Device.DIER.SetBits(stm32.TIM_DIER_UIE) - - return nil -} - -// Sets a callback to be called when a channel reaches it's set-point. -// -// For example, if `t.Set(ch, t.Top() / 4)` is used then the callback will -// be called every quarter-period of the timer's base Period. -func (t *TIM) SetMatchInterrupt(channel uint8, callback ChannelCallback) error { - t.channelCallbacks[channel] = callback - - // Ensure the interrupt handler for Output Compare events is registered - t.OCInterrupt = t.registerOCInterrupt() - - // Clear the interrupt flag - t.Device.SR.ClearBits(stm32.TIM_SR_CC1IF << channel) - - // Enable the interrupt - t.OCInterrupt.SetPriority(0xc1) - t.OCInterrupt.Enable() - - // Enable the hardware interrupt - t.Device.DIER.SetBits(stm32.TIM_DIER_CC1IE << channel) - - return nil -} - -// SetPeriod updates the period of this PWM peripheral. -// To set a particular frequency, use the following formula: -// -// period = 1e9 / frequency -// -// If you use a period of 0, a period that works well for LEDs will be picked. -// -// SetPeriod will not change the prescaler, but also won't change the current -// value in any of the channels. This means that you may need to update the -// value for the particular channel. -// -// Note that you cannot pick any arbitrary period after the PWM peripheral has -// been configured. If you want to switch between frequencies, pick the lowest -// frequency (longest period) once when calling Configure and adjust the -// frequency here as needed. -func (t *TIM) SetPeriod(period uint64) error { - return t.setPeriod(period, false) -} - -func (t *TIM) setPeriod(period uint64, updatePrescaler bool) error { - var top uint64 - if period == 0 { - top = ARR_MAX - } else { - top = (period / 1000) * (t.busFreq / 1000) / 1000 - } - - var psc uint64 - if updatePrescaler { - if top > ARR_MAX*PSC_MAX { - return ErrPWMPeriodTooLong - } - - // Select the minimum PSC that scales the ARR value into - // range to maintain precision in ARR for changing frequencies - // later - psc = ceil(top, ARR_MAX) - top = top / psc - - t.Device.PSC.Set(uint32(psc - 1)) - } else { - psc = uint64(t.Device.PSC.Get()) + 1 - top = top / psc - - if top > ARR_MAX { - return ErrPWMPeriodTooLong - } - } - - t.Device.ARR.Set(arrtype(top - 1)) - return nil -} - -// Top returns the current counter top, for use in duty cycle calculation. It -// will only change with a call to Configure or SetPeriod, otherwise it is -// constant. -// -// The value returned here is hardware dependent. In general, it's best to treat -// it as an opaque value that can be divided by some number and passed to -// pwm.Set (see pwm.Set for more information). -func (t *TIM) Top() uint32 { - return uint32(t.Device.ARR.Get()) + 1 -} - -// Channel returns a PWM channel for the given pin. -func (t *TIM) Channel(pin Pin) (uint8, error) { - - for chi, ch := range t.Channels { - for _, p := range ch.Pins { - if p.Pin == pin { - t.configurePin(uint8(chi), p) - //p.Pin.ConfigureAltFunc(PinConfig{Mode: PinModePWMOutput}, p.AltFunc) - return uint8(chi), nil - } - } - } - - return 0, ErrInvalidOutputPin -} - -// Set updates the channel value. This is used to control the channel duty -// cycle. For example, to set it to a 25% duty cycle, use: -// -// t.Set(ch, t.Top() / 4) -// -// ch.Set(0) will set the output to low and ch.Set(ch.Top()) will set the output -// to high, assuming the output isn't inverted. -func (t *TIM) Set(channel uint8, value uint32) { - t.enableMainOutput() - - ccr := t.channelCCR(channel) - ccmr, offset := t.channelCCMR(channel) - - // Disable interrupts whilst programming to prevent spurious OC interrupts - mask := interrupt.Disable() - - // Set the PWM to Mode 1 (active below set value, inactive above) - // Preload is disabled so we can change OC value within one update period. - var ccmrVal uint32 - ccmrVal |= PWM_MODE1 << stm32.TIM_CCMR1_Output_OC1M_Pos - ccmr.ReplaceBits(ccmrVal, 0xFF, offset) - - // Set the compare value - ccr.Set(arrtype(value)) - - // Enable the channel (if not already) - t.Device.CCER.ReplaceBits(stm32.TIM_CCER_CC1E, 0xD, channel*4) - - // Force update - t.Device.EGR.SetBits(stm32.TIM_EGR_CC1G << channel) - - // Reset Interrupt Flag - t.Device.SR.ClearBits(stm32.TIM_SR_CC1IF << channel) - - // Restore interrupts - interrupt.Restore(mask) -} - -// Unset disables a channel, including any configured interrupts. -func (t *TIM) Unset(channel uint8) { - // Disable interrupts whilst programming to prevent spurious OC interrupts - mask := interrupt.Disable() - - // Disable the channel - t.Device.CCER.ReplaceBits(0, 0xD, channel*4) - - // Reset to zero value - ccr := t.channelCCR(channel) - ccr.Set(0) - - // Disable the hardware interrupt - t.Device.DIER.ClearBits(stm32.TIM_DIER_CC1IE << channel) - - // Clear the interrupt flag - t.Device.SR.ClearBits(stm32.TIM_SR_CC1IF << channel) - - // Restore interrupts - interrupt.Restore(mask) -} - -// SetInverting sets whether to invert the output of this channel. -// Without inverting, a 25% duty cycle would mean the output is high for 25% of -// the time and low for the rest. Inverting flips the output as if a NOT gate -// was placed at the output, meaning that the output would be 25% low and 75% -// high with a duty cycle of 25%. -func (t *TIM) SetInverting(channel uint8, inverting bool) { - // Enable the channel (if not already) - - var val = uint32(0) - if inverting { - val |= stm32.TIM_CCER_CC1P - } - - t.Device.CCER.ReplaceBits(val, stm32.TIM_CCER_CC1P_Msk, channel*4) -} - -func (t *TIM) handleUPInterrupt(interrupt.Interrupt) { - if t.Device.SR.HasBits(stm32.TIM_SR_UIF) { - // clear the update flag - t.Device.SR.ClearBits(stm32.TIM_SR_UIF) - - if t.wraparoundCallback != nil { - t.wraparoundCallback() - } - } -} - -func (t *TIM) handleOCInterrupt(interrupt.Interrupt) { - if t.Device.SR.HasBits(stm32.TIM_SR_CC1IF) { - if t.channelCallbacks[0] != nil { - t.channelCallbacks[0](0) - } - } - if t.Device.SR.HasBits(stm32.TIM_SR_CC2IF) { - if t.channelCallbacks[1] != nil { - t.channelCallbacks[1](1) - } - } - if t.Device.SR.HasBits(stm32.TIM_SR_CC3IF) { - if t.channelCallbacks[2] != nil { - t.channelCallbacks[2](2) - } - } - if t.Device.SR.HasBits(stm32.TIM_SR_CC4IF) { - if t.channelCallbacks[3] != nil { - t.channelCallbacks[3](3) - } - } - - // Reset interrupt flags - t.Device.SR.ClearBits(stm32.TIM_SR_CC1IF | stm32.TIM_SR_CC2IF | stm32.TIM_SR_CC3IF | stm32.TIM_SR_CC4IF) -} - -func (t *TIM) channelCCR(channel uint8) *arrRegType { - switch channel { - case 0: - return &t.Device.CCR1 - case 1: - return &t.Device.CCR2 - case 2: - return &t.Device.CCR3 - case 3: - return &t.Device.CCR4 - } - - return nil -} - -func (t *TIM) channelCCMR(channel uint8) (reg *volatile.Register32, offset uint8) { - switch channel { - case 0: - return &t.Device.CCMR1_Output, 0 - case 1: - return &t.Device.CCMR1_Output, 8 - case 2: - return &t.Device.CCMR2_Output, 0 - case 3: - return &t.Device.CCMR2_Output, 8 - } - - return nil, 0 -} - -//go:inline -func ceil(num uint64, denom uint64) uint64 { - return (num + denom - 1) / denom -} diff --git a/emb/machine/machine_stm32_tim_moder.go b/emb/machine/machine_stm32_tim_moder.go deleted file mode 100644 index 5cb360d..0000000 --- a/emb/machine/machine_stm32_tim_moder.go +++ /dev/null @@ -1,10 +0,0 @@ -//go:build stm32 && !stm32f1 - -package machine - -// Configuration of a GPIO pin for PWM output for STM32 MCUs with MODER -// register (most MCUs except STM32F1 series). - -func (t *TIM) configurePin(channel uint8, pf PinFunction) { - pf.Pin.ConfigureAltFunc(PinConfig{Mode: PinModePWMOutput}, pf.AltFunc) -} diff --git a/emb/machine/machine_stm32_uart.go b/emb/machine/machine_stm32_uart.go deleted file mode 100644 index 6e8806c..0000000 --- a/emb/machine/machine_stm32_uart.go +++ /dev/null @@ -1,85 +0,0 @@ -//go:build stm32 - -package machine - -// Peripheral abstraction layer for UARTs on the stm32 family. - -import ( - "device/stm32" - "runtime/interrupt" - "runtime/volatile" - "unsafe" -) - -// UART representation -type UART struct { - Buffer *RingBuffer - Bus *stm32.USART_Type - Interrupt interrupt.Interrupt - TxAltFuncSelector uint8 - RxAltFuncSelector uint8 - - // Registers specific to the chip - rxReg *volatile.Register32 - txReg *volatile.Register32 - statusReg *volatile.Register32 - txEmptyFlag uint32 -} - -// Configure the UART. -func (uart *UART) Configure(config UARTConfig) { - // Default baud rate to 115200. - if config.BaudRate == 0 { - config.BaudRate = 115200 - } - - // Set the GPIO pins to defaults if they're not set - if config.TX == 0 && config.RX == 0 { - config.TX = UART_TX_PIN - config.RX = UART_RX_PIN - } - - // STM32 families have different, but compatible, registers for - // basic UART functions. For each family populate the registers - // into `uart`. - uart.setRegisters() - - // Enable USART clock - enableAltFuncClock(unsafe.Pointer(uart.Bus)) - - uart.configurePins(config) - - // Set baud rate - uart.SetBaudRate(config.BaudRate) - - // Enable USART port, tx, rx and rx interrupts - uart.Bus.CR1.Set(stm32.USART_CR1_TE | stm32.USART_CR1_RE | stm32.USART_CR1_RXNEIE | stm32.USART_CR1_UE) - - // Enable RX IRQ - uart.Interrupt.SetPriority(0xc0) - uart.Interrupt.Enable() -} - -// handleInterrupt should be called from the appropriate interrupt handler for -// this UART instance. -func (uart *UART) handleInterrupt(interrupt.Interrupt) { - uart.Receive(byte((uart.rxReg.Get() & 0xFF))) -} - -// SetBaudRate sets the communication speed for the UART. Defer to chip-specific -// routines for calculation -func (uart *UART) SetBaudRate(br uint32) { - divider := uart.getBaudRateDivisor(br) - uart.Bus.BRR.Set(divider) -} - -// WriteByte writes a byte of data to the UART. -func (uart *UART) writeByte(c byte) error { - uart.txReg.Set(uint32(c)) - - for !uart.statusReg.HasBits(uart.txEmptyFlag) { - } - return nil -} - -func (uart *UART) flush() {} diff --git a/emb/machine/machine_stm32f103.go b/emb/machine/machine_stm32f103.go deleted file mode 100644 index 9e7bb34..0000000 --- a/emb/machine/machine_stm32f103.go +++ /dev/null @@ -1,739 +0,0 @@ -//go:build stm32 && stm32f103 - -package machine - -// Peripheral abstraction layer for the stm32. - -import ( - "device/stm32" - "runtime/interrupt" - "runtime/volatile" - "unsafe" -) - -func CPUFrequency() uint32 { - return 72000000 -} - -var deviceIDAddr = []uintptr{0x1FFFF7E8, 0x1FFFF7EC, 0x1FFFF7F0} - -// Internal use: configured speed of the APB1 and APB2 timers, this should be kept -// in sync with any changes to runtime package which configures the oscillators -// and clock frequencies -const APB1_TIM_FREQ = 72e6 // 72MHz -const APB2_TIM_FREQ = 72e6 // 72MHz - -const ( - PinInput PinMode = 0 // Input mode - PinOutput10MHz PinMode = 1 // Output mode, max speed 10MHz - PinOutput2MHz PinMode = 2 // Output mode, max speed 2MHz - PinOutput50MHz PinMode = 3 // Output mode, max speed 50MHz - PinOutput PinMode = PinOutput2MHz - - PinInputModeAnalog PinMode = 0 // Input analog mode - PinInputModeFloating PinMode = 4 // Input floating mode - PinInputModePullUpDown PinMode = 8 // Input pull up/down mode - PinInputModeReserved PinMode = 12 // Input mode (reserved) - - PinOutputModeGPPushPull PinMode = 0 // Output mode general purpose push/pull - PinOutputModeGPOpenDrain PinMode = 4 // Output mode general purpose open drain - PinOutputModeAltPushPull PinMode = 8 // Output mode alt. purpose push/pull - PinOutputModeAltOpenDrain PinMode = 12 // Output mode alt. purpose open drain - - // Pull-up vs Pull down is not part of the CNF0 / CNF1 bits, but is - // controlled by PxODR. Encoded using the 'spare' bit 5. - PinInputPulldown PinMode = PinInputModePullUpDown - PinInputPullup PinMode = PinInputModePullUpDown | 0x10 -) - -// Pin constants for all stm32f103 package sizes -const ( - PA0 = portA + 0 - PA1 = portA + 1 - PA2 = portA + 2 - PA3 = portA + 3 - PA4 = portA + 4 - PA5 = portA + 5 - PA6 = portA + 6 - PA7 = portA + 7 - PA8 = portA + 8 - PA9 = portA + 9 - PA10 = portA + 10 - PA11 = portA + 11 - PA12 = portA + 12 - PA13 = portA + 13 - PA14 = portA + 14 - PA15 = portA + 15 - - PB0 = portB + 0 - PB1 = portB + 1 - PB2 = portB + 2 - PB3 = portB + 3 - PB4 = portB + 4 - PB5 = portB + 5 - PB6 = portB + 6 - PB7 = portB + 7 - PB8 = portB + 8 - PB9 = portB + 9 - PB10 = portB + 10 - PB11 = portB + 11 - PB12 = portB + 12 - PB13 = portB + 13 - PB14 = portB + 14 - PB15 = portB + 15 - - PC0 = portC + 0 - PC1 = portC + 1 - PC2 = portC + 2 - PC3 = portC + 3 - PC4 = portC + 4 - PC5 = portC + 5 - PC6 = portC + 6 - PC7 = portC + 7 - PC8 = portC + 8 - PC9 = portC + 9 - PC10 = portC + 10 - PC11 = portC + 11 - PC12 = portC + 12 - PC13 = portC + 13 - PC14 = portC + 14 - PC15 = portC + 15 - - PD0 = portD + 0 - PD1 = portD + 1 - PD2 = portD + 2 - PD3 = portD + 3 - PD4 = portD + 4 - PD5 = portD + 5 - PD6 = portD + 6 - PD7 = portD + 7 - PD8 = portD + 8 - PD9 = portD + 9 - PD10 = portD + 10 - PD11 = portD + 11 - PD12 = portD + 12 - PD13 = portD + 13 - PD14 = portD + 14 - PD15 = portD + 15 - - PE0 = portE + 0 - PE1 = portE + 1 - PE2 = portE + 2 - PE3 = portE + 3 - PE4 = portE + 4 - PE5 = portE + 5 - PE6 = portE + 6 - PE7 = portE + 7 - PE8 = portE + 8 - PE9 = portE + 9 - PE10 = portE + 10 - PE11 = portE + 11 - PE12 = portE + 12 - PE13 = portE + 13 - PE14 = portE + 14 - PE15 = portE + 15 - - PF0 = portF + 0 - PF1 = portF + 1 - PF2 = portF + 2 - PF3 = portF + 3 - PF4 = portF + 4 - PF5 = portF + 5 - PF6 = portF + 6 - PF7 = portF + 7 - PF8 = portF + 8 - PF9 = portF + 9 - PF10 = portF + 10 - PF11 = portF + 11 - PF12 = portF + 12 - PF13 = portF + 13 - PF14 = portF + 14 - PF15 = portF + 15 -) - -// Configure this pin with the given I/O settings. -// stm32f1xx uses different technique for setting the GPIO pins than the stm32f407 -func (p Pin) Configure(config PinConfig) { - // Configure the GPIO pin. - p.enableClock() - port := p.getPort() - pin := uint8(p) % 16 - pos := (pin % 8) * 4 - if pin < 8 { - port.CRL.ReplaceBits(uint32(config.Mode), 0xf, pos) - } else { - port.CRH.ReplaceBits(uint32(config.Mode), 0xf, pos) - } - - // If configured for input pull-up or pull-down, set ODR - // for desired pull-up or pull-down. - if (config.Mode & 0xf) == PinInputModePullUpDown { - var pullup uint32 - if config.Mode == PinInputPullup { - pullup = 1 - } - port.ODR.ReplaceBits(pullup, 0x1, pin) - } -} - -func (p Pin) getPort() *stm32.GPIO_Type { - switch p / 16 { - case 0: - return stm32.GPIOA - case 1: - return stm32.GPIOB - case 2: - return stm32.GPIOC - case 3: - return stm32.GPIOD - case 4: - return stm32.GPIOE - case 5: - return stm32.GPIOF - case 6: - return stm32.GPIOG - default: - panic("machine: unknown port") - } -} - -// enableClock enables the clock for this desired GPIO port. -func (p Pin) enableClock() { - switch p / 16 { - case 0: - stm32.RCC.APB2ENR.SetBits(stm32.RCC_APB2ENR_IOPAEN) - case 1: - stm32.RCC.APB2ENR.SetBits(stm32.RCC_APB2ENR_IOPBEN) - case 2: - stm32.RCC.APB2ENR.SetBits(stm32.RCC_APB2ENR_IOPCEN) - case 3: - stm32.RCC.APB2ENR.SetBits(stm32.RCC_APB2ENR_IOPDEN) - case 4: - stm32.RCC.APB2ENR.SetBits(stm32.RCC_APB2ENR_IOPEEN) - case 5: - stm32.RCC.APB2ENR.SetBits(stm32.RCC_APB2ENR_IOPFEN) - case 6: - stm32.RCC.APB2ENR.SetBits(stm32.RCC_APB2ENR_IOPGEN) - default: - panic("machine: unknown port") - } -} - -// Enable peripheral clock. Expand to include all the desired peripherals -func enableAltFuncClock(bus unsafe.Pointer) { - switch bus { - case unsafe.Pointer(stm32.USART1): - stm32.RCC.APB2ENR.SetBits(stm32.RCC_APB2ENR_USART1EN) - case unsafe.Pointer(stm32.USART2): - stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_USART2EN) - case unsafe.Pointer(stm32.I2C1): - stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_I2C1EN) - case unsafe.Pointer(stm32.SPI1): - stm32.RCC.APB2ENR.SetBits(stm32.RCC_APB2ENR_SPI1EN) - case unsafe.Pointer(stm32.ADC1): - stm32.RCC.APB2ENR.SetBits(stm32.RCC_APB2ENR_ADC1EN) - default: - panic("machine: unknown peripheral") - } -} - -func (p Pin) registerInterrupt() interrupt.Interrupt { - pin := uint8(p) % 16 - - switch pin { - case 0: - return interrupt.New(stm32.IRQ_EXTI0, func(interrupt.Interrupt) { handlePinInterrupt(0) }) - case 1: - return interrupt.New(stm32.IRQ_EXTI1, func(interrupt.Interrupt) { handlePinInterrupt(1) }) - case 2: - return interrupt.New(stm32.IRQ_EXTI2, func(interrupt.Interrupt) { handlePinInterrupt(2) }) - case 3: - return interrupt.New(stm32.IRQ_EXTI3, func(interrupt.Interrupt) { handlePinInterrupt(3) }) - case 4: - return interrupt.New(stm32.IRQ_EXTI4, func(interrupt.Interrupt) { handlePinInterrupt(4) }) - case 5: - return interrupt.New(stm32.IRQ_EXTI9_5, func(interrupt.Interrupt) { handlePinInterrupt(5) }) - case 6: - return interrupt.New(stm32.IRQ_EXTI9_5, func(interrupt.Interrupt) { handlePinInterrupt(6) }) - case 7: - return interrupt.New(stm32.IRQ_EXTI9_5, func(interrupt.Interrupt) { handlePinInterrupt(7) }) - case 8: - return interrupt.New(stm32.IRQ_EXTI9_5, func(interrupt.Interrupt) { handlePinInterrupt(8) }) - case 9: - return interrupt.New(stm32.IRQ_EXTI9_5, func(interrupt.Interrupt) { handlePinInterrupt(9) }) - case 10: - return interrupt.New(stm32.IRQ_EXTI15_10, func(interrupt.Interrupt) { handlePinInterrupt(10) }) - case 11: - return interrupt.New(stm32.IRQ_EXTI15_10, func(interrupt.Interrupt) { handlePinInterrupt(11) }) - case 12: - return interrupt.New(stm32.IRQ_EXTI15_10, func(interrupt.Interrupt) { handlePinInterrupt(12) }) - case 13: - return interrupt.New(stm32.IRQ_EXTI15_10, func(interrupt.Interrupt) { handlePinInterrupt(13) }) - case 14: - return interrupt.New(stm32.IRQ_EXTI15_10, func(interrupt.Interrupt) { handlePinInterrupt(14) }) - case 15: - return interrupt.New(stm32.IRQ_EXTI15_10, func(interrupt.Interrupt) { handlePinInterrupt(15) }) - } - - return interrupt.Interrupt{} -} - -//---------- UART related code - -// Configure the TX and RX pins -func (uart *UART) configurePins(config UARTConfig) { - - // pins - switch config.TX { - case UART_ALT_TX_PIN: - // use alternate TX/RX pins via AFIO mapping - stm32.RCC.APB2ENR.SetBits(stm32.RCC_APB2ENR_AFIOEN) - if uart.Bus == stm32.USART1 { - stm32.AFIO.MAPR.SetBits(stm32.AFIO_MAPR_USART1_REMAP) - } else if uart.Bus == stm32.USART2 { - stm32.AFIO.MAPR.SetBits(stm32.AFIO_MAPR_USART2_REMAP) - } - default: - // use standard TX/RX pins PA9 and PA10 - } - config.TX.Configure(PinConfig{Mode: PinOutput50MHz + PinOutputModeAltPushPull}) - config.RX.Configure(PinConfig{Mode: PinInputModeFloating}) -} - -// Determine the divisor for USARTs to get the given baudrate -func (uart *UART) getBaudRateDivisor(br uint32) uint32 { - - // Note: PCLK2 (from APB2) used for USART1 and PCLK1 for USART2, 3, 4, 5 - var divider uint32 - if uart.Bus == stm32.USART1 { - // first divide by PCLK2 prescaler (div 1) and then desired baudrate - divider = CPUFrequency() / br - } else { - // first divide by PCLK1 prescaler (div 2) and then desired baudrate - divider = CPUFrequency() / 2 / br - } - return divider -} - -// Register names vary by ST processor, these are for STM F103xx -func (uart *UART) setRegisters() { - uart.rxReg = &uart.Bus.DR - uart.txReg = &uart.Bus.DR - uart.statusReg = &uart.Bus.SR - uart.txEmptyFlag = stm32.USART_SR_TXE -} - -//---------- SPI related types and code - -type SPI struct { - Bus *stm32.SPI_Type -} - -// There are 3 SPI interfaces on the STM32F103xx. -// Since the first interface is named SPI1, both SPI0 and SPI1 refer to SPI1. -// TODO: implement SPI2 and SPI3. -var ( - SPI1 = &SPI{Bus: stm32.SPI1} - SPI0 = SPI1 -) - -func (spi *SPI) config8Bits() { - // no-op on this series -} - -// Set baud rate for SPI -func (spi *SPI) getBaudRate(config SPIConfig) uint32 { - var conf uint32 - - // set frequency dependent on PCLK2 prescaler (div 1) - switch { - case config.Frequency < 125000: - // Note: impossible to achieve lower frequency with current PCLK2! - conf |= stm32.SPI_CR1_BR_Div256 - case config.Frequency < 250000: - conf |= stm32.SPI_CR1_BR_Div256 - case config.Frequency < 500000: - conf |= stm32.SPI_CR1_BR_Div128 - case config.Frequency < 1000000: - conf |= stm32.SPI_CR1_BR_Div64 - case config.Frequency < 2000000: - conf |= stm32.SPI_CR1_BR_Div32 - case config.Frequency < 4000000: - conf |= stm32.SPI_CR1_BR_Div16 - default: - // When its bigger than Div16, just round to the maximum frequency. - conf |= stm32.SPI_CR1_BR_Div8 - } - return conf << stm32.SPI_CR1_BR_Pos -} - -// Configure SPI pins for input output and clock -func (spi *SPI) configurePins(config SPIConfig) { - config.SCK.Configure(PinConfig{Mode: PinOutput50MHz + PinOutputModeAltPushPull}) - config.SDO.Configure(PinConfig{Mode: PinOutput50MHz + PinOutputModeAltPushPull}) - config.SDI.Configure(PinConfig{Mode: PinInputModeFloating}) -} - -//---------- I2C related types and code - -// There are 2 I2C interfaces on the STM32F103xx. -// Since the first interface is named I2C1, both I2C0 and I2C1 refer to I2C1. -// TODO: implement I2C2. - -type I2C struct { - Bus *stm32.I2C_Type -} - -var ( - I2C1 = &I2C{Bus: stm32.I2C1} - I2C0 = I2C1 -) - -func (i2c *I2C) configurePins(config I2CConfig) { - if config.SDA == PB9 { - // use alternate I2C1 pins PB8/PB9 via AFIO mapping - stm32.RCC.APB2ENR.SetBits(stm32.RCC_APB2ENR_AFIOEN) - stm32.AFIO.MAPR.SetBits(stm32.AFIO_MAPR_I2C1_REMAP) - } - - config.SDA.Configure(PinConfig{Mode: PinOutput50MHz + PinOutputModeAltOpenDrain}) - config.SCL.Configure(PinConfig{Mode: PinOutput50MHz + PinOutputModeAltOpenDrain}) -} - -func (i2c *I2C) getFreqRange(config I2CConfig) uint32 { - // pclk1 clock speed is main frequency divided by PCLK1 prescaler (div 2) - pclk1 := CPUFrequency() / 2 - - // set frequency range to PCLK1 clock speed in MHz - // aka setting the value 36 means to use 36 MHz clock - return pclk1 / 1000000 -} - -func (i2c *I2C) getRiseTime(config I2CConfig) uint32 { - // These bits must be programmed with the maximum SCL rise time given in the - // I2C bus specification, incremented by 1. - // For instance: in Sm mode, the maximum allowed SCL rise time is 1000 ns. - // If, in the I2C_CR2 register, the value of FREQ[5:0] bits is equal to 0x08 - // and PCLK1 = 125 ns, therefore the TRISE[5:0] bits must be programmed with - // 09h (1000 ns / 125 ns = 8 + 1) - freqRange := i2c.getFreqRange(config) - if config.Frequency > 100000 { - // fast mode (Fm) adjustment - freqRange *= 300 - freqRange /= 1000 - } - return (freqRange + 1) << stm32.I2C_TRISE_TRISE_Pos -} - -func (i2c *I2C) getSpeed(config I2CConfig) uint32 { - ccr := func(pclk uint32, freq uint32, coeff uint32) uint32 { - return (((pclk - 1) / (freq * coeff)) + 1) & stm32.I2C_CCR_CCR_Msk - } - sm := func(pclk uint32, freq uint32) uint32 { // standard mode (Sm) - if s := ccr(pclk, freq, 2); s < 4 { - return 4 - } else { - return s - } - } - fm := func(pclk uint32, freq uint32, duty uint8) uint32 { // fast mode (Fm) - if duty == DutyCycle2 { - return ccr(pclk, freq, 3) - } else { - return ccr(pclk, freq, 25) | stm32.I2C_CCR_DUTY - } - } - clock := CPUFrequency() / 2 - if config.Frequency <= 100000 { - return sm(clock, config.Frequency) - } else { - s := fm(clock, config.Frequency, config.DutyCycle) - if (s & stm32.I2C_CCR_CCR_Msk) == 0 { - return 1 - } else { - return s | stm32.I2C_CCR_F_S - } - } -} - -//---------- Timer related code - -// For Pin Mappings see RM0008, pg 179 -// https://www.st.com/resource/en/reference_manual/cd00171190-stm32f101xx-stm32f102xx-stm32f103xx-stm32f105xx-and-stm32f107xx-advanced-arm-based-32-bit-mcus-stmicroelectronics.pdf -// -// Note: for STM32F1 series the pin mapping is done 'per timer' not per channel, -// not all channels on a timer have the same degrees of flexibility, and some -// combinations are only available on some packages - so care is needed at app -// level to ensure valid combinations of pins are used. -// - -var ( - TIM1 = TIM{ - EnableRegister: &stm32.RCC.APB2ENR, - EnableFlag: stm32.RCC_APB2ENR_TIM1EN, - Device: stm32.TIM1, - Channels: [4]TimerChannel{ - TimerChannel{Pins: []PinFunction{{PE9, 0b11}, {PA8, 0b00}}}, - TimerChannel{Pins: []PinFunction{{PE11, 0b11}, {PA9, 0b00}}}, - TimerChannel{Pins: []PinFunction{{PE13, 0b11}, {PA10, 0b00}}}, - TimerChannel{Pins: []PinFunction{{PE14, 0b11}, {PA11, 0b00}}}, - }, - busFreq: APB2_TIM_FREQ, - } - - TIM2 = TIM{ - EnableRegister: &stm32.RCC.APB1ENR, - EnableFlag: stm32.RCC_APB1ENR_TIM2EN, - Device: stm32.TIM2, - Channels: [4]TimerChannel{ - TimerChannel{Pins: []PinFunction{{PA0, 0b00}, {PA15, 0b01}}}, - TimerChannel{Pins: []PinFunction{{PA1, 0b00}, {PB3, 0b01}}}, - TimerChannel{Pins: []PinFunction{{PA2, 0b00}, {PB10, 0b10}}}, - TimerChannel{Pins: []PinFunction{{PA3, 0b00}, {PB11, 0b10}}}, - }, - busFreq: APB1_TIM_FREQ, - } - - TIM3 = TIM{ - EnableRegister: &stm32.RCC.APB1ENR, - EnableFlag: stm32.RCC_APB1ENR_TIM3EN, - Device: stm32.TIM3, - Channels: [4]TimerChannel{ - TimerChannel{Pins: []PinFunction{{PA6, 0b00}, {PC6, 0b11}, {PB4, 0b10}}}, - TimerChannel{Pins: []PinFunction{{PA7, 0b00}, {PC7, 0b11}, {PB5, 0b10}}}, - TimerChannel{Pins: []PinFunction{{PB0, 0b00}, {PC8, 0b11}}}, - TimerChannel{Pins: []PinFunction{{PB1, 0b00}, {PC9, 0b11}}}, - }, - busFreq: APB1_TIM_FREQ, - } - - TIM4 = TIM{ - EnableRegister: &stm32.RCC.APB1ENR, - EnableFlag: stm32.RCC_APB1ENR_TIM4EN, - Device: stm32.TIM4, - Channels: [4]TimerChannel{ - TimerChannel{Pins: []PinFunction{{PD12, 0b1}, {PB6, 0}}}, - TimerChannel{Pins: []PinFunction{{PD13, 0b1}, {PB7, 0}}}, - TimerChannel{Pins: []PinFunction{{PD14, 0b1}, {PB8, 0}}}, - TimerChannel{Pins: []PinFunction{{PD15, 0b1}, {PB9, 0}}}, - }, - busFreq: APB1_TIM_FREQ, - } - - TIM5 = TIM{ - EnableRegister: &stm32.RCC.APB1ENR, - EnableFlag: stm32.RCC_APB1ENR_TIM5EN, - Device: stm32.TIM5, - Channels: [4]TimerChannel{ - TimerChannel{Pins: []PinFunction{}}, - TimerChannel{Pins: []PinFunction{}}, - TimerChannel{Pins: []PinFunction{}}, - TimerChannel{Pins: []PinFunction{{PA3, 0b0}}}, - }, - busFreq: APB1_TIM_FREQ, - } - - TIM6 = TIM{ - EnableRegister: &stm32.RCC.APB1ENR, - EnableFlag: stm32.RCC_APB1ENR_TIM6EN, - Device: stm32.TIM6, - Channels: [4]TimerChannel{ - TimerChannel{Pins: []PinFunction{}}, - TimerChannel{Pins: []PinFunction{}}, - TimerChannel{Pins: []PinFunction{}}, - TimerChannel{Pins: []PinFunction{}}, - }, - busFreq: APB1_TIM_FREQ, - } - - TIM7 = TIM{ - EnableRegister: &stm32.RCC.APB1ENR, - EnableFlag: stm32.RCC_APB1ENR_TIM7EN, - Device: stm32.TIM7, - Channels: [4]TimerChannel{ - TimerChannel{Pins: []PinFunction{}}, - TimerChannel{Pins: []PinFunction{}}, - TimerChannel{Pins: []PinFunction{}}, - TimerChannel{Pins: []PinFunction{}}, - }, - busFreq: APB1_TIM_FREQ, - } - - TIM8 = TIM{ - EnableRegister: &stm32.RCC.APB2ENR, - EnableFlag: stm32.RCC_APB2ENR_TIM8EN, - Device: stm32.TIM8, - Channels: [4]TimerChannel{ - TimerChannel{Pins: []PinFunction{}}, - TimerChannel{Pins: []PinFunction{}}, - TimerChannel{Pins: []PinFunction{}}, - TimerChannel{Pins: []PinFunction{}}, - }, - busFreq: APB2_TIM_FREQ, - } - - TIM9 = TIM{ - EnableRegister: &stm32.RCC.APB2ENR, - EnableFlag: stm32.RCC_APB2ENR_TIM9EN, - Device: stm32.TIM9, - Channels: [4]TimerChannel{ - TimerChannel{Pins: []PinFunction{{PA2, 0b0}, {PE5, 0b1}}}, - TimerChannel{Pins: []PinFunction{{PA3, 0b0}, {PE6, 0b1}}}, - TimerChannel{Pins: []PinFunction{}}, - TimerChannel{Pins: []PinFunction{}}, - }, - busFreq: APB2_TIM_FREQ, - } - - TIM10 = TIM{ - EnableRegister: &stm32.RCC.APB2ENR, - EnableFlag: stm32.RCC_APB2ENR_TIM10EN, - Device: stm32.TIM10, - Channels: [4]TimerChannel{ - TimerChannel{Pins: []PinFunction{{PB8, 0b0}, {PF6, 0b1}}}, - TimerChannel{Pins: []PinFunction{}}, - TimerChannel{Pins: []PinFunction{}}, - TimerChannel{Pins: []PinFunction{}}, - }, - busFreq: APB2_TIM_FREQ, - } - - TIM11 = TIM{ - EnableRegister: &stm32.RCC.APB2ENR, - EnableFlag: stm32.RCC_APB2ENR_TIM11EN, - Device: stm32.TIM11, - Channels: [4]TimerChannel{ - TimerChannel{Pins: []PinFunction{{PB9, 0b0}, {PF7, 0b1}}}, - TimerChannel{Pins: []PinFunction{}}, - TimerChannel{Pins: []PinFunction{}}, - TimerChannel{Pins: []PinFunction{}}, - }, - busFreq: APB2_TIM_FREQ, - } - - TIM12 = TIM{ - EnableRegister: &stm32.RCC.APB1ENR, - EnableFlag: stm32.RCC_APB1ENR_TIM12EN, - Device: stm32.TIM12, - Channels: [4]TimerChannel{ - TimerChannel{Pins: []PinFunction{{}}}, - TimerChannel{Pins: []PinFunction{}}, - TimerChannel{Pins: []PinFunction{}}, - TimerChannel{Pins: []PinFunction{}}, - }, - busFreq: APB1_TIM_FREQ, - } - - TIM13 = TIM{ - EnableRegister: &stm32.RCC.APB1ENR, - EnableFlag: stm32.RCC_APB1ENR_TIM13EN, - Device: stm32.TIM13, - Channels: [4]TimerChannel{ - TimerChannel{Pins: []PinFunction{{PA6, 0b0}, {PF8, 0b1}}}, - TimerChannel{Pins: []PinFunction{}}, - TimerChannel{Pins: []PinFunction{}}, - TimerChannel{Pins: []PinFunction{}}, - }, - busFreq: APB1_TIM_FREQ, - } - - TIM14 = TIM{ - EnableRegister: &stm32.RCC.APB1ENR, - EnableFlag: stm32.RCC_APB1ENR_TIM14EN, - Device: stm32.TIM14, - Channels: [4]TimerChannel{ - TimerChannel{Pins: []PinFunction{{PA7, 0b0}, {PF9, 0b1}}}, - TimerChannel{Pins: []PinFunction{}}, - TimerChannel{Pins: []PinFunction{}}, - TimerChannel{Pins: []PinFunction{}}, - }, - busFreq: APB1_TIM_FREQ, - } -) - -func (t *TIM) registerUPInterrupt() interrupt.Interrupt { - switch t { - case &TIM1: - return interrupt.New(stm32.IRQ_TIM1_UP, TIM1.handleUPInterrupt) - case &TIM2: - return interrupt.New(stm32.IRQ_TIM2, TIM2.handleUPInterrupt) - case &TIM3: - return interrupt.New(stm32.IRQ_TIM3, TIM3.handleUPInterrupt) - case &TIM4: - return interrupt.New(stm32.IRQ_TIM4, TIM4.handleUPInterrupt) - case &TIM5: - return interrupt.New(stm32.IRQ_TIM5, TIM5.handleUPInterrupt) - case &TIM6: - return interrupt.New(stm32.IRQ_TIM6, TIM6.handleUPInterrupt) - case &TIM7: - return interrupt.New(stm32.IRQ_TIM7, TIM7.handleUPInterrupt) - case &TIM8: - return interrupt.New(stm32.IRQ_TIM8_UP, TIM8.handleUPInterrupt) - } - - return interrupt.Interrupt{} -} - -func (t *TIM) registerOCInterrupt() interrupt.Interrupt { - switch t { - case &TIM1: - return interrupt.New(stm32.IRQ_TIM1_CC, TIM1.handleOCInterrupt) - case &TIM2: - return interrupt.New(stm32.IRQ_TIM2, TIM2.handleOCInterrupt) - case &TIM3: - return interrupt.New(stm32.IRQ_TIM3, TIM3.handleOCInterrupt) - case &TIM4: - return interrupt.New(stm32.IRQ_TIM4, TIM4.handleOCInterrupt) - case &TIM5: - return interrupt.New(stm32.IRQ_TIM5, TIM5.handleOCInterrupt) - case &TIM6: - return interrupt.New(stm32.IRQ_TIM6, TIM6.handleOCInterrupt) - case &TIM7: - return interrupt.New(stm32.IRQ_TIM7, TIM7.handleOCInterrupt) - case &TIM8: - return interrupt.New(stm32.IRQ_TIM8_CC, TIM8.handleOCInterrupt) - } - - return interrupt.Interrupt{} -} - -func (t *TIM) configurePin(channel uint8, pf PinFunction) { - remap := uint32(pf.AltFunc) - - switch t { - case &TIM1: - stm32.AFIO.MAPR.ReplaceBits(remap< clock { - freq = clock - } - - // calculate the exact clock divisor (freq=clock/div -> div=clock/freq). - // truncation is fine, since it produces a less-than-or-equal divisor, and - // thus a greater-than-or-equal frequency. - // divisors only come in consecutive powers of 2, so we can use log2 (or, - // equivalently, bits.Len - 1) to convert to respective enum value. - div := bits.Len32(clock/freq) - 1 - - // but DIV1 (2^0) is not permitted, as the least divisor is DIV2 (2^1), so - // subtract 1 from the log2 value, keeping a lower bound of 0 - if div < 0 { - div = 0 - } else if div > 0 { - div-- - } - - // finally, shift the enumerated value into position for SPI CR1 - return uint32(div) << stm32.SPI_CR1_BR_Pos -} - -// -- I2C ---------------------------------------------------------------------- - -type I2C struct { - Bus *stm32.I2C_Type - AltFuncSelector uint8 -} - -func (i2c *I2C) configurePins(config I2CConfig) { - config.SCL.ConfigureAltFunc(PinConfig{Mode: PinModeI2CSCL}, i2c.AltFuncSelector) - config.SDA.ConfigureAltFunc(PinConfig{Mode: PinModeI2CSDA}, i2c.AltFuncSelector) -} - -func (i2c *I2C) getFreqRange(config I2CConfig) uint32 { - // all I2C interfaces are on APB1 - clock := CPUFrequency() / 4 - // convert to MHz - clock /= 1000000 - // must be between 2 MHz (or 4 MHz for fast mode (Fm)) and 50 MHz, inclusive - var min, max uint32 = 2, 50 - if config.Frequency > 100000 { - min = 4 // fast mode (Fm) - } - if clock < min { - clock = min - } else if clock > max { - clock = max - } - return clock << stm32.I2C_CR2_FREQ_Pos -} - -func (i2c *I2C) getRiseTime(config I2CConfig) uint32 { - // These bits must be programmed with the maximum SCL rise time given in the - // I2C bus specification, incremented by 1. - // For instance: in Sm mode, the maximum allowed SCL rise time is 1000 ns. - // If, in the I2C_CR2 register, the value of FREQ[5:0] bits is equal to 0x08 - // and PCLK1 = 125 ns, therefore the TRISE[5:0] bits must be programmed with - // 09h (1000 ns / 125 ns = 8 + 1) - freqRange := i2c.getFreqRange(config) - if config.Frequency > 100000 { - // fast mode (Fm) adjustment - freqRange *= 300 - freqRange /= 1000 - } - return (freqRange + 1) << stm32.I2C_TRISE_TRISE_Pos -} - -func (i2c *I2C) getSpeed(config I2CConfig) uint32 { - ccr := func(pclk uint32, freq uint32, coeff uint32) uint32 { - return (((pclk - 1) / (freq * coeff)) + 1) & stm32.I2C_CCR_CCR_Msk - } - sm := func(pclk uint32, freq uint32) uint32 { // standard mode (Sm) - if s := ccr(pclk, freq, 2); s < 4 { - return 4 - } else { - return s - } - } - fm := func(pclk uint32, freq uint32, duty uint8) uint32 { // fast mode (Fm) - if duty == DutyCycle2 { - return ccr(pclk, freq, 3) - } else { - return ccr(pclk, freq, 25) | stm32.I2C_CCR_DUTY - } - } - // all I2C interfaces are on APB1 - clock := CPUFrequency() / 4 - if config.Frequency <= 100000 { - return sm(clock, config.Frequency) - } else { - s := fm(clock, config.Frequency, config.DutyCycle) - if (s & stm32.I2C_CCR_CCR_Msk) == 0 { - return 1 - } else { - return s | stm32.I2C_CCR_F_S - } - } -} - -//---------- Flash related code - -// the block size actually depends on the sector. -// TODO: handle this correctly for sectors > 3 -const eraseBlockSizeValue = 16384 - -// see RM0090 page 75 -func sectorNumber(address uintptr) uint32 { - switch { - // 0x0800 0000 - 0x0800 3FFF - case address >= 0x08000000 && address <= 0x08003FFF: - return 0 - // 0x0800 4000 - 0x0800 7FFF - case address >= 0x08004000 && address <= 0x08007FFF: - return 1 - // 0x0800 8000 - 0x0800 BFFF - case address >= 0x08008000 && address <= 0x0800BFFF: - return 2 - // 0x0800 C000 - 0x0800 FFFF - case address >= 0x0800C000 && address <= 0x0800FFFF: - return 3 - // 0x0801 0000 - 0x0801 FFFF - case address >= 0x08010000 && address <= 0x0801FFFF: - return 4 - // 0x0802 0000 - 0x0803 FFFF - case address >= 0x08020000 && address <= 0x0803FFFF: - return 5 - // 0x0804 0000 - 0x0805 FFFF - case address >= 0x08040000 && address <= 0x0805FFFF: - return 6 - case address >= 0x08060000 && address <= 0x0807FFFF: - return 7 - case address >= 0x08080000 && address <= 0x0809FFFF: - return 8 - case address >= 0x080A0000 && address <= 0x080BFFFF: - return 9 - case address >= 0x080C0000 && address <= 0x080DFFFF: - return 10 - case address >= 0x080E0000 && address <= 0x080FFFFF: - return 11 - default: - return 0 - } -} - -// calculate sector number from address -// var sector uint32 = sectorNumber(address) - -// see RM0090 page 85 -// eraseBlock at the passed in block number -func eraseBlock(block uint32) error { - waitUntilFlashDone() - - // clear any previous errors - stm32.FLASH.SR.SetBits(0xF0) - - // set SER bit - stm32.FLASH.SetCR_SER(1) - defer stm32.FLASH.SetCR_SER(0) - - // set the block (aka sector) to be erased - stm32.FLASH.SetCR_SNB(block) - defer stm32.FLASH.SetCR_SNB(0) - - // start the page erase - stm32.FLASH.SetCR_STRT(1) - - waitUntilFlashDone() - - if err := checkError(); err != nil { - return err - } - - return nil -} - -const writeBlockSize = 2 - -// see RM0090 page 86 -// must write data in word-length -func writeFlashData(address uintptr, data []byte) (int, error) { - if len(data)%writeBlockSize != 0 { - return 0, errFlashInvalidWriteLength - } - - waitUntilFlashDone() - - // clear any previous errors - stm32.FLASH.SR.SetBits(0xF0) - - // set parallelism to x32 - stm32.FLASH.SetCR_PSIZE(2) - - for i := 0; i < len(data); i += writeBlockSize { - // start write operation - stm32.FLASH.SetCR_PG(1) - - *(*uint16)(unsafe.Pointer(address)) = binary.LittleEndian.Uint16(data[i : i+writeBlockSize]) - - waitUntilFlashDone() - - if err := checkError(); err != nil { - return i, err - } - - // end write operation - stm32.FLASH.SetCR_PG(0) - } - - return len(data), nil -} - -func waitUntilFlashDone() { - for stm32.FLASH.GetSR_BSY() != 0 { - } -} - -var ( - errFlashPGS = errors.New("errFlashPGS") - errFlashPGP = errors.New("errFlashPGP") - errFlashPGA = errors.New("errFlashPGA") - errFlashWRP = errors.New("errFlashWRP") -) - -func checkError() error { - switch { - case stm32.FLASH.GetSR_PGSERR() != 0: - return errFlashPGS - case stm32.FLASH.GetSR_PGPERR() != 0: - return errFlashPGP - case stm32.FLASH.GetSR_PGAERR() != 0: - return errFlashPGA - case stm32.FLASH.GetSR_WRPERR() != 0: - return errFlashWRP - } - - return nil -} diff --git a/emb/machine/machine_stm32f40x.go b/emb/machine/machine_stm32f40x.go deleted file mode 100644 index 953c7fa..0000000 --- a/emb/machine/machine_stm32f40x.go +++ /dev/null @@ -1,13 +0,0 @@ -//go:build stm32f4 && (stm32f405 || stm32f407) - -package machine - -func CPUFrequency() uint32 { - return 168000000 -} - -// Internal use: configured speed of the APB1 and APB2 timers, this should be kept -// in sync with any changes to runtime package which configures the oscillators -// and clock frequencies -const APB1_TIM_FREQ = 42000000 * 2 -const APB2_TIM_FREQ = 84000000 * 2 diff --git a/emb/machine/machine_stm32f469.go b/emb/machine/machine_stm32f469.go deleted file mode 100644 index dfda91f..0000000 --- a/emb/machine/machine_stm32f469.go +++ /dev/null @@ -1,13 +0,0 @@ -//go:build stm32f4 && stm32f469 - -package machine - -func CPUFrequency() uint32 { - return 180000000 -} - -// Internal use: configured speed of the APB1 and APB2 timers, this should be kept -// in sync with any changes to runtime package which configures the oscillators -// and clock frequencies -const APB1_TIM_FREQ = 45000000 * 2 -const APB2_TIM_FREQ = 90000000 * 2 diff --git a/emb/machine/machine_stm32f7.go b/emb/machine/machine_stm32f7.go deleted file mode 100644 index 11eff11..0000000 --- a/emb/machine/machine_stm32f7.go +++ /dev/null @@ -1,725 +0,0 @@ -//go:build stm32f7 - -package machine - -// Peripheral abstraction layer for the stm32f4 - -import ( - "device/stm32" - "runtime/interrupt" - "runtime/volatile" - "unsafe" -) - -var deviceIDAddr = []uintptr{0x1FF0F420, 0x1FF0F424, 0x1FF0F428} - -// Alternative peripheral pin functions -const ( - AF0_SYSTEM = 0 - AF1_TIM1_2 = 1 - AF2_TIM3_4_5 = 2 - AF3_TIM8_9_10_11_LPTIM1 = 3 - AF4_I2C1_2_3_USART1 = 4 - AF5_SPI1_2_3_4_5_I2S1_2_3 = 5 - AF6_SPI2_3_I2S2_3_SAI1_UART4 = 6 - AF7_SPI2_3_I2S2_3_USART1_2_3_UART5 = 7 - AF8_SAI2_USART6_UART4_5_7_8_OTG1_FS = 8 - AF9_CAN1_TIM12_13_14_QUADSPI_FMC_OTG2_HS = 9 - AF10_SAI2_QUADSPI_SDMMC2_OTG2_HS_OTG1_FS = 10 - AF11_SDMMC2 = 11 - AF12_UART7_FMC_SDMMC1_OTG2_FS = 12 - AF15_EVENTOUT = 15 -) - -const ( - PA0 = portA + 0 - PA1 = portA + 1 - PA2 = portA + 2 - PA3 = portA + 3 - PA4 = portA + 4 - PA5 = portA + 5 - PA6 = portA + 6 - PA7 = portA + 7 - PA8 = portA + 8 - PA9 = portA + 9 - PA10 = portA + 10 - PA11 = portA + 11 - PA12 = portA + 12 - PA13 = portA + 13 - PA14 = portA + 14 - PA15 = portA + 15 - - PB0 = portB + 0 - PB1 = portB + 1 - PB2 = portB + 2 - PB3 = portB + 3 - PB4 = portB + 4 - PB5 = portB + 5 - PB6 = portB + 6 - PB7 = portB + 7 - PB8 = portB + 8 - PB9 = portB + 9 - PB10 = portB + 10 - PB11 = portB + 11 - PB12 = portB + 12 - PB13 = portB + 13 - PB14 = portB + 14 - PB15 = portB + 15 - - PC0 = portC + 0 - PC1 = portC + 1 - PC2 = portC + 2 - PC3 = portC + 3 - PC4 = portC + 4 - PC5 = portC + 5 - PC6 = portC + 6 - PC7 = portC + 7 - PC8 = portC + 8 - PC9 = portC + 9 - PC10 = portC + 10 - PC11 = portC + 11 - PC12 = portC + 12 - PC13 = portC + 13 - PC14 = portC + 14 - PC15 = portC + 15 - - PD0 = portD + 0 - PD1 = portD + 1 - PD2 = portD + 2 - PD3 = portD + 3 - PD4 = portD + 4 - PD5 = portD + 5 - PD6 = portD + 6 - PD7 = portD + 7 - PD8 = portD + 8 - PD9 = portD + 9 - PD10 = portD + 10 - PD11 = portD + 11 - PD12 = portD + 12 - PD13 = portD + 13 - PD14 = portD + 14 - PD15 = portD + 15 - - PE0 = portE + 0 - PE1 = portE + 1 - PE2 = portE + 2 - PE3 = portE + 3 - PE4 = portE + 4 - PE5 = portE + 5 - PE6 = portE + 6 - PE7 = portE + 7 - PE8 = portE + 8 - PE9 = portE + 9 - PE10 = portE + 10 - PE11 = portE + 11 - PE12 = portE + 12 - PE13 = portE + 13 - PE14 = portE + 14 - PE15 = portE + 15 - - PF0 = portF + 0 - PF1 = portF + 1 - PF2 = portF + 2 - PF3 = portF + 3 - PF4 = portF + 4 - PF5 = portF + 5 - PF6 = portF + 6 - PF7 = portF + 7 - PF8 = portF + 8 - PF9 = portF + 9 - PF10 = portF + 10 - PF11 = portF + 11 - PF12 = portF + 12 - PF13 = portF + 13 - PF14 = portF + 14 - PF15 = portF + 15 - - PG0 = portG + 0 - PG1 = portG + 1 - PG2 = portG + 2 - PG3 = portG + 3 - PG4 = portG + 4 - PG5 = portG + 5 - PG6 = portG + 6 - PG7 = portG + 7 - PG8 = portG + 8 - PG9 = portG + 9 - PG10 = portG + 10 - PG11 = portG + 11 - PG12 = portG + 12 - PG13 = portG + 13 - PG14 = portG + 14 - PG15 = portG + 15 - - PH0 = portH + 0 - PH1 = portH + 1 - PH2 = portH + 2 - PH3 = portH + 3 - PH4 = portH + 4 - PH5 = portH + 5 - PH6 = portH + 6 - PH7 = portH + 7 - PH8 = portH + 8 - PH9 = portH + 9 - PH10 = portH + 10 - PH11 = portH + 11 - PH12 = portH + 12 - PH13 = portH + 13 - PH14 = portH + 14 - PH15 = portH + 15 - - PI0 = portI + 0 - PI1 = portI + 1 - PI2 = portI + 2 - PI3 = portI + 3 - PI4 = portI + 4 - PI5 = portI + 5 - PI6 = portI + 6 - PI7 = portI + 7 - PI8 = portI + 8 - PI9 = portI + 9 - PI10 = portI + 10 - PI11 = portI + 11 - PI12 = portI + 12 - PI13 = portI + 13 - PI14 = portI + 14 - PI15 = portI + 15 -) - -func (p Pin) getPort() *stm32.GPIO_Type { - switch p / 16 { - case 0: - return stm32.GPIOA - case 1: - return stm32.GPIOB - case 2: - return stm32.GPIOC - case 3: - return stm32.GPIOD - case 4: - return stm32.GPIOE - case 5: - return stm32.GPIOF - case 6: - return stm32.GPIOG - case 7: - return stm32.GPIOH - case 8: - return stm32.GPIOI - default: - panic("machine: unknown port") - } -} - -// enableClock enables the clock for this desired GPIO port. -func (p Pin) enableClock() { - switch p / 16 { - case 0: - stm32.RCC.AHB1ENR.SetBits(stm32.RCC_AHB1ENR_GPIOAEN) - case 1: - stm32.RCC.AHB1ENR.SetBits(stm32.RCC_AHB1ENR_GPIOBEN) - case 2: - stm32.RCC.AHB1ENR.SetBits(stm32.RCC_AHB1ENR_GPIOCEN) - case 3: - stm32.RCC.AHB1ENR.SetBits(stm32.RCC_AHB1ENR_GPIODEN) - case 4: - stm32.RCC.AHB1ENR.SetBits(stm32.RCC_AHB1ENR_GPIOEEN) - case 5: - stm32.RCC.AHB1ENR.SetBits(stm32.RCC_AHB1ENR_GPIOFEN) - case 6: - stm32.RCC.AHB1ENR.SetBits(stm32.RCC_AHB1ENR_GPIOGEN) - case 7: - stm32.RCC.AHB1ENR.SetBits(stm32.RCC_AHB1ENR_GPIOHEN) - case 8: - stm32.RCC.AHB1ENR.SetBits(stm32.RCC_AHB1ENR_GPIOIEN) - default: - panic("machine: unknown port") - } -} - -// Enable peripheral clock -func enableAltFuncClock(bus unsafe.Pointer) { - switch bus { - case unsafe.Pointer(stm32.DAC): // DAC interface clock enable - stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_DACEN) - case unsafe.Pointer(stm32.PWR): // Power interface clock enable - stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_PWREN) - case unsafe.Pointer(stm32.CAN1): // CAN 1 clock enable - stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_CAN1EN) - case unsafe.Pointer(stm32.I2C3): // I2C3 clock enable - stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_I2C3EN) - case unsafe.Pointer(stm32.I2C2): // I2C2 clock enable - stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_I2C2EN) - case unsafe.Pointer(stm32.I2C1): // I2C1 clock enable - stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_I2C1EN) - case unsafe.Pointer(stm32.UART5): // UART5 clock enable - stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_UART5EN) - case unsafe.Pointer(stm32.UART4): // UART4 clock enable - stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_UART4EN) - case unsafe.Pointer(stm32.USART3): // USART3 clock enable - stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_USART3EN) - case unsafe.Pointer(stm32.USART2): // USART2 clock enable - stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_USART2EN) - case unsafe.Pointer(stm32.SPI3): // SPI3 clock enable - stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_SPI3EN) - case unsafe.Pointer(stm32.SPI2): // SPI2 clock enable - stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_SPI2EN) - case unsafe.Pointer(stm32.WWDG): // Window watchdog clock enable - stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_WWDGEN) - case unsafe.Pointer(stm32.TIM14): // TIM14 clock enable - stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_TIM14EN) - case unsafe.Pointer(stm32.TIM13): // TIM13 clock enable - stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_TIM13EN) - case unsafe.Pointer(stm32.TIM12): // TIM12 clock enable - stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_TIM12EN) - case unsafe.Pointer(stm32.TIM7): // TIM7 clock enable - stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_TIM7EN) - case unsafe.Pointer(stm32.TIM6): // TIM6 clock enable - stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_TIM6EN) - case unsafe.Pointer(stm32.TIM5): // TIM5 clock enable - stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_TIM5EN) - case unsafe.Pointer(stm32.TIM4): // TIM4 clock enable - stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_TIM4EN) - case unsafe.Pointer(stm32.TIM3): // TIM3 clock enable - stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_TIM3EN) - case unsafe.Pointer(stm32.TIM2): // TIM2 clock enable - stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_TIM2EN) - case unsafe.Pointer(stm32.TIM11): // TIM11 clock enable - stm32.RCC.APB2ENR.SetBits(stm32.RCC_APB2ENR_TIM11EN) - case unsafe.Pointer(stm32.TIM10): // TIM10 clock enable - stm32.RCC.APB2ENR.SetBits(stm32.RCC_APB2ENR_TIM10EN) - case unsafe.Pointer(stm32.TIM9): // TIM9 clock enable - stm32.RCC.APB2ENR.SetBits(stm32.RCC_APB2ENR_TIM9EN) - case unsafe.Pointer(stm32.SYSCFG): // System configuration controller clock enable - stm32.RCC.APB2ENR.SetBits(stm32.RCC_APB2ENR_SYSCFGEN) - case unsafe.Pointer(stm32.SPI1): // SPI1 clock enable - stm32.RCC.APB2ENR.SetBits(stm32.RCC_APB2ENR_SPI1EN) - case unsafe.Pointer(stm32.ADC3): // ADC3 clock enable - stm32.RCC.APB2ENR.SetBits(stm32.RCC_APB2ENR_ADC3EN) - case unsafe.Pointer(stm32.ADC2): // ADC2 clock enable - stm32.RCC.APB2ENR.SetBits(stm32.RCC_APB2ENR_ADC2EN) - case unsafe.Pointer(stm32.ADC1): // ADC1 clock enable - stm32.RCC.APB2ENR.SetBits(stm32.RCC_APB2ENR_ADC1EN) - case unsafe.Pointer(stm32.USART6): // USART6 clock enable - stm32.RCC.APB2ENR.SetBits(stm32.RCC_APB2ENR_USART6EN) - case unsafe.Pointer(stm32.USART1): // USART1 clock enable - stm32.RCC.APB2ENR.SetBits(stm32.RCC_APB2ENR_USART1EN) - case unsafe.Pointer(stm32.TIM8): // TIM8 clock enable - stm32.RCC.APB2ENR.SetBits(stm32.RCC_APB2ENR_TIM8EN) - case unsafe.Pointer(stm32.TIM1): // TIM1 clock enable - stm32.RCC.APB2ENR.SetBits(stm32.RCC_APB2ENR_TIM1EN) - } -} - -func (p Pin) registerInterrupt() interrupt.Interrupt { - pin := uint8(p) % 16 - - switch pin { - case 0: - return interrupt.New(stm32.IRQ_EXTI0, func(interrupt.Interrupt) { handlePinInterrupt(0) }) - case 1: - return interrupt.New(stm32.IRQ_EXTI1, func(interrupt.Interrupt) { handlePinInterrupt(1) }) - case 2: - return interrupt.New(stm32.IRQ_EXTI2, func(interrupt.Interrupt) { handlePinInterrupt(2) }) - case 3: - return interrupt.New(stm32.IRQ_EXTI3, func(interrupt.Interrupt) { handlePinInterrupt(3) }) - case 4: - return interrupt.New(stm32.IRQ_EXTI4, func(interrupt.Interrupt) { handlePinInterrupt(4) }) - case 5: - return interrupt.New(stm32.IRQ_EXTI9_5, func(interrupt.Interrupt) { handlePinInterrupt(5) }) - case 6: - return interrupt.New(stm32.IRQ_EXTI9_5, func(interrupt.Interrupt) { handlePinInterrupt(6) }) - case 7: - return interrupt.New(stm32.IRQ_EXTI9_5, func(interrupt.Interrupt) { handlePinInterrupt(7) }) - case 8: - return interrupt.New(stm32.IRQ_EXTI9_5, func(interrupt.Interrupt) { handlePinInterrupt(8) }) - case 9: - return interrupt.New(stm32.IRQ_EXTI9_5, func(interrupt.Interrupt) { handlePinInterrupt(9) }) - case 10: - return interrupt.New(stm32.IRQ_EXTI15_10, func(interrupt.Interrupt) { handlePinInterrupt(10) }) - case 11: - return interrupt.New(stm32.IRQ_EXTI15_10, func(interrupt.Interrupt) { handlePinInterrupt(11) }) - case 12: - return interrupt.New(stm32.IRQ_EXTI15_10, func(interrupt.Interrupt) { handlePinInterrupt(12) }) - case 13: - return interrupt.New(stm32.IRQ_EXTI15_10, func(interrupt.Interrupt) { handlePinInterrupt(13) }) - case 14: - return interrupt.New(stm32.IRQ_EXTI15_10, func(interrupt.Interrupt) { handlePinInterrupt(14) }) - case 15: - return interrupt.New(stm32.IRQ_EXTI15_10, func(interrupt.Interrupt) { handlePinInterrupt(15) }) - } - - return interrupt.Interrupt{} -} - -//---------- Timer related code - -var ( - TIM1 = TIM{ - EnableRegister: &stm32.RCC.APB2ENR, - EnableFlag: stm32.RCC_APB2ENR_TIM1EN, - Device: stm32.TIM1, - Channels: [4]TimerChannel{ - TimerChannel{Pins: []PinFunction{ - {PA8, AF1_TIM1_2}, - {PE9, AF1_TIM1_2}, - }}, - TimerChannel{Pins: []PinFunction{ - {PA9, AF1_TIM1_2}, - {PE11, AF1_TIM1_2}, - }}, - TimerChannel{Pins: []PinFunction{ - {PA10, AF1_TIM1_2}, - {PE13, AF1_TIM1_2}, - }}, - TimerChannel{Pins: []PinFunction{ - {PA11, AF1_TIM1_2}, - {PE14, AF1_TIM1_2}, - }}, - }, - busFreq: APB2_TIM_FREQ, - } - - TIM2 = TIM{ - EnableRegister: &stm32.RCC.APB1ENR, - EnableFlag: stm32.RCC_APB1ENR_TIM2EN, - Device: stm32.TIM2, - Channels: [4]TimerChannel{ - TimerChannel{Pins: []PinFunction{ - {PA0, AF1_TIM1_2}, - {PA5, AF1_TIM1_2}, - {PA15, AF1_TIM1_2}, - }}, - TimerChannel{Pins: []PinFunction{ - {PA1, AF1_TIM1_2}, - {PB3, AF1_TIM1_2}, - }}, - TimerChannel{Pins: []PinFunction{ - {PA2, AF1_TIM1_2}, - {PB10, AF1_TIM1_2}, - }}, - TimerChannel{Pins: []PinFunction{ - {PA3, AF1_TIM1_2}, - {PB11, AF1_TIM1_2}, - }}, - }, - busFreq: APB1_TIM_FREQ, - } - - TIM3 = TIM{ - EnableRegister: &stm32.RCC.APB1ENR, - EnableFlag: stm32.RCC_APB1ENR_TIM3EN, - Device: stm32.TIM3, - Channels: [4]TimerChannel{ - TimerChannel{Pins: []PinFunction{ - {PA6, AF2_TIM3_4_5}, - {PB4, AF2_TIM3_4_5}, - {PC6, AF2_TIM3_4_5}, - }}, - TimerChannel{Pins: []PinFunction{ - {PA7, AF2_TIM3_4_5}, - {PB5, AF2_TIM3_4_5}, - {PC7, AF2_TIM3_4_5}, - }}, - TimerChannel{Pins: []PinFunction{ - {PB0, AF2_TIM3_4_5}, - {PC8, AF2_TIM3_4_5}, - }}, - TimerChannel{Pins: []PinFunction{ - {PB1, AF2_TIM3_4_5}, - {PC9, AF2_TIM3_4_5}, - }}, - }, - busFreq: APB1_TIM_FREQ, - } - - TIM4 = TIM{ - EnableRegister: &stm32.RCC.APB1ENR, - EnableFlag: stm32.RCC_APB1ENR_TIM4EN, - Device: stm32.TIM4, - Channels: [4]TimerChannel{ - TimerChannel{Pins: []PinFunction{ - {PB6, AF2_TIM3_4_5}, - {PD12, AF2_TIM3_4_5}, - }}, - TimerChannel{Pins: []PinFunction{ - {PB7, AF2_TIM3_4_5}, - {PD13, AF2_TIM3_4_5}, - }}, - TimerChannel{Pins: []PinFunction{ - {PB8, AF2_TIM3_4_5}, - {PD14, AF2_TIM3_4_5}, - }}, - TimerChannel{Pins: []PinFunction{ - {PB9, AF2_TIM3_4_5}, - {PD15, AF2_TIM3_4_5}, - }}, - }, - busFreq: APB1_TIM_FREQ, - } - - TIM5 = TIM{ - EnableRegister: &stm32.RCC.APB1ENR, - EnableFlag: stm32.RCC_APB1ENR_TIM5EN, - Device: stm32.TIM5, - Channels: [4]TimerChannel{ - TimerChannel{Pins: []PinFunction{ - {PA0, AF2_TIM3_4_5}, - {PH10, AF2_TIM3_4_5}, - }}, - TimerChannel{Pins: []PinFunction{ - {PA1, AF2_TIM3_4_5}, - {PH11, AF2_TIM3_4_5}, - }}, - TimerChannel{Pins: []PinFunction{ - {PA2, AF2_TIM3_4_5}, - {PH12, AF2_TIM3_4_5}, - }}, - TimerChannel{Pins: []PinFunction{ - {PA3, AF2_TIM3_4_5}, - {PI0, AF2_TIM3_4_5}, - }}, - }, - busFreq: APB1_TIM_FREQ, - } - - TIM6 = TIM{ - EnableRegister: &stm32.RCC.APB1ENR, - EnableFlag: stm32.RCC_APB1ENR_TIM6EN, - Device: stm32.TIM6, - Channels: [4]TimerChannel{ - TimerChannel{Pins: []PinFunction{}}, - TimerChannel{Pins: []PinFunction{}}, - TimerChannel{Pins: []PinFunction{}}, - TimerChannel{Pins: []PinFunction{}}, - }, - busFreq: APB1_TIM_FREQ, - } - - TIM7 = TIM{ - EnableRegister: &stm32.RCC.APB1ENR, - EnableFlag: stm32.RCC_APB1ENR_TIM7EN, - Device: stm32.TIM7, - Channels: [4]TimerChannel{ - TimerChannel{Pins: []PinFunction{}}, - TimerChannel{Pins: []PinFunction{}}, - TimerChannel{Pins: []PinFunction{}}, - TimerChannel{Pins: []PinFunction{}}, - }, - busFreq: APB1_TIM_FREQ, - } - - TIM8 = TIM{ - EnableRegister: &stm32.RCC.APB2ENR, - EnableFlag: stm32.RCC_APB2ENR_TIM8EN, - Device: stm32.TIM8, - Channels: [4]TimerChannel{ - TimerChannel{Pins: []PinFunction{ - {PC6, AF3_TIM8_9_10_11_LPTIM1}, - {PI5, AF3_TIM8_9_10_11_LPTIM1}, - }}, - TimerChannel{Pins: []PinFunction{ - {PC7, AF3_TIM8_9_10_11_LPTIM1}, - {PI6, AF3_TIM8_9_10_11_LPTIM1}, - }}, - TimerChannel{Pins: []PinFunction{ - {PC8, AF3_TIM8_9_10_11_LPTIM1}, - {PI7, AF3_TIM8_9_10_11_LPTIM1}, - }}, - TimerChannel{Pins: []PinFunction{ - {PC9, AF3_TIM8_9_10_11_LPTIM1}, - {PI2, AF3_TIM8_9_10_11_LPTIM1}, - }}, - }, - busFreq: APB2_TIM_FREQ, - } - - TIM9 = TIM{ - EnableRegister: &stm32.RCC.APB2ENR, - EnableFlag: stm32.RCC_APB2ENR_TIM9EN, - Device: stm32.TIM9, - Channels: [4]TimerChannel{ - TimerChannel{Pins: []PinFunction{ - {PA2, AF3_TIM8_9_10_11_LPTIM1}, - {PE5, AF3_TIM8_9_10_11_LPTIM1}, - }}, - TimerChannel{Pins: []PinFunction{ - {PA3, AF3_TIM8_9_10_11_LPTIM1}, - {PE6, AF3_TIM8_9_10_11_LPTIM1}, - }}, - TimerChannel{Pins: []PinFunction{}}, - TimerChannel{Pins: []PinFunction{}}, - }, - busFreq: APB2_TIM_FREQ, - } - - TIM10 = TIM{ - EnableRegister: &stm32.RCC.APB2ENR, - EnableFlag: stm32.RCC_APB2ENR_TIM10EN, - Device: stm32.TIM10, - Channels: [4]TimerChannel{ - TimerChannel{Pins: []PinFunction{ - {PB8, AF3_TIM8_9_10_11_LPTIM1}, - {PF6, AF3_TIM8_9_10_11_LPTIM1}, - }}, - TimerChannel{Pins: []PinFunction{}}, - TimerChannel{Pins: []PinFunction{}}, - TimerChannel{Pins: []PinFunction{}}, - }, - busFreq: APB2_TIM_FREQ, - } - - TIM11 = TIM{ - EnableRegister: &stm32.RCC.APB2ENR, - EnableFlag: stm32.RCC_APB2ENR_TIM11EN, - Device: stm32.TIM11, - Channels: [4]TimerChannel{ - TimerChannel{Pins: []PinFunction{ - {PB9, AF3_TIM8_9_10_11_LPTIM1}, - {PF7, AF3_TIM8_9_10_11_LPTIM1}, - }}, - TimerChannel{Pins: []PinFunction{}}, - TimerChannel{Pins: []PinFunction{}}, - TimerChannel{Pins: []PinFunction{}}, - }, - busFreq: APB2_TIM_FREQ, - } - - TIM12 = TIM{ - EnableRegister: &stm32.RCC.APB1ENR, - EnableFlag: stm32.RCC_APB1ENR_TIM12EN, - Device: stm32.TIM12, - Channels: [4]TimerChannel{ - TimerChannel{Pins: []PinFunction{ - {PB14, AF9_CAN1_TIM12_13_14_QUADSPI_FMC_OTG2_HS}, - {PH6, AF9_CAN1_TIM12_13_14_QUADSPI_FMC_OTG2_HS}, - }}, - TimerChannel{Pins: []PinFunction{ - {PB15, AF9_CAN1_TIM12_13_14_QUADSPI_FMC_OTG2_HS}, - {PH9, AF9_CAN1_TIM12_13_14_QUADSPI_FMC_OTG2_HS}, - }}, - TimerChannel{Pins: []PinFunction{}}, - TimerChannel{Pins: []PinFunction{}}, - }, - busFreq: APB1_TIM_FREQ, - } - - TIM13 = TIM{ - EnableRegister: &stm32.RCC.APB1ENR, - EnableFlag: stm32.RCC_APB1ENR_TIM13EN, - Device: stm32.TIM13, - Channels: [4]TimerChannel{ - TimerChannel{Pins: []PinFunction{ - {PA6, AF9_CAN1_TIM12_13_14_QUADSPI_FMC_OTG2_HS}, - {PF8, AF9_CAN1_TIM12_13_14_QUADSPI_FMC_OTG2_HS}, - }}, - TimerChannel{Pins: []PinFunction{}}, - TimerChannel{Pins: []PinFunction{}}, - TimerChannel{Pins: []PinFunction{}}, - }, - busFreq: APB1_TIM_FREQ, - } - - TIM14 = TIM{ - EnableRegister: &stm32.RCC.APB1ENR, - EnableFlag: stm32.RCC_APB1ENR_TIM14EN, - Device: stm32.TIM14, - Channels: [4]TimerChannel{ - TimerChannel{Pins: []PinFunction{ - {PA7, AF9_CAN1_TIM12_13_14_QUADSPI_FMC_OTG2_HS}, - {PF9, AF9_CAN1_TIM12_13_14_QUADSPI_FMC_OTG2_HS}, - }}, - TimerChannel{Pins: []PinFunction{}}, - TimerChannel{Pins: []PinFunction{}}, - TimerChannel{Pins: []PinFunction{}}, - }, - busFreq: APB1_TIM_FREQ, - } -) - -func (t *TIM) registerUPInterrupt() interrupt.Interrupt { - switch t { - case &TIM1: - return interrupt.New(stm32.IRQ_TIM1_UP_TIM10, TIM1.handleUPInterrupt) - case &TIM2: - return interrupt.New(stm32.IRQ_TIM2, TIM2.handleUPInterrupt) - case &TIM3: - return interrupt.New(stm32.IRQ_TIM3, TIM3.handleUPInterrupt) - case &TIM4: - return interrupt.New(stm32.IRQ_TIM4, TIM4.handleUPInterrupt) - case &TIM5: - return interrupt.New(stm32.IRQ_TIM5, TIM5.handleUPInterrupt) - case &TIM6: - return interrupt.New(stm32.IRQ_TIM6_DAC, TIM6.handleUPInterrupt) - case &TIM7: - return interrupt.New(stm32.IRQ_TIM7, TIM7.handleUPInterrupt) - case &TIM8: - return interrupt.New(stm32.IRQ_TIM8_UP_TIM13, TIM8.handleUPInterrupt) - case &TIM9: - return interrupt.New(stm32.IRQ_TIM1_BRK_TIM9, TIM9.handleUPInterrupt) - case &TIM10: - return interrupt.New(stm32.IRQ_TIM1_UP_TIM10, TIM10.handleUPInterrupt) - case &TIM11: - return interrupt.New(stm32.IRQ_TIM1_TRG_COM_TIM11, TIM11.handleUPInterrupt) - case &TIM12: - return interrupt.New(stm32.IRQ_TIM8_BRK_TIM12, TIM12.handleUPInterrupt) - case &TIM13: - return interrupt.New(stm32.IRQ_TIM8_UP_TIM13, TIM13.handleUPInterrupt) - case &TIM14: - return interrupt.New(stm32.IRQ_TIM8_TRG_COM_TIM14, TIM14.handleUPInterrupt) - } - - return interrupt.Interrupt{} -} - -func (t *TIM) registerOCInterrupt() interrupt.Interrupt { - switch t { - case &TIM1: - return interrupt.New(stm32.IRQ_TIM1_CC, TIM1.handleUPInterrupt) - case &TIM2: - return interrupt.New(stm32.IRQ_TIM2, TIM2.handleOCInterrupt) - case &TIM3: - return interrupt.New(stm32.IRQ_TIM3, TIM3.handleOCInterrupt) - case &TIM4: - return interrupt.New(stm32.IRQ_TIM4, TIM4.handleOCInterrupt) - case &TIM5: - return interrupt.New(stm32.IRQ_TIM5, TIM5.handleOCInterrupt) - case &TIM6: - return interrupt.New(stm32.IRQ_TIM6_DAC, TIM6.handleOCInterrupt) - case &TIM7: - return interrupt.New(stm32.IRQ_TIM7, TIM7.handleOCInterrupt) - case &TIM8: - return interrupt.New(stm32.IRQ_TIM8_CC, TIM8.handleOCInterrupt) - case &TIM9: - return interrupt.New(stm32.IRQ_TIM1_BRK_TIM9, TIM9.handleOCInterrupt) - case &TIM10: - return interrupt.New(stm32.IRQ_TIM1_UP_TIM10, TIM10.handleOCInterrupt) - case &TIM11: - return interrupt.New(stm32.IRQ_TIM1_TRG_COM_TIM11, TIM11.handleOCInterrupt) - case &TIM12: - return interrupt.New(stm32.IRQ_TIM8_BRK_TIM12, TIM12.handleOCInterrupt) - case &TIM13: - return interrupt.New(stm32.IRQ_TIM8_UP_TIM13, TIM13.handleOCInterrupt) - case &TIM14: - return interrupt.New(stm32.IRQ_TIM8_TRG_COM_TIM14, TIM14.handleOCInterrupt) - } - - return interrupt.Interrupt{} -} - -func (t *TIM) enableMainOutput() { - t.Device.BDTR.SetBits(stm32.TIM_BDTR_MOE) -} - -type arrtype = uint32 -type arrRegType = volatile.Register32 - -const ( - ARR_MAX = 0x10000 - PSC_MAX = 0x10000 -) - -func initRNG() { - stm32.RCC.AHB2ENR.SetBits(stm32.RCC_AHB2ENR_RNGEN) - stm32.RNG.CR.SetBits(stm32.RNG_CR_RNGEN) -} diff --git a/emb/machine/machine_stm32f7x2.go b/emb/machine/machine_stm32f7x2.go deleted file mode 100644 index 7da4070..0000000 --- a/emb/machine/machine_stm32f7x2.go +++ /dev/null @@ -1,70 +0,0 @@ -//go:build stm32f7x2 - -package machine - -// Peripheral abstraction layer for the stm32f407 - -import ( - "device/stm32" -) - -func CPUFrequency() uint32 { - return 216000000 -} - -// Internal use: configured speed of the APB1 and APB2 timers, this should be kept -// in sync with any changes to runtime package which configures the oscillators -// and clock frequencies -const APB1_TIM_FREQ = 54e6 // 54MHz -const APB2_TIM_FREQ = 216e6 // 216MHz - -//---------- UART related code - -// Configure the UART. -func (uart *UART) configurePins(config UARTConfig) { - // enable the alternate functions on the TX and RX pins - config.TX.ConfigureAltFunc(PinConfig{Mode: PinModeUARTTX}, uart.TxAltFuncSelector) - config.RX.ConfigureAltFunc(PinConfig{Mode: PinModeUARTRX}, uart.RxAltFuncSelector) -} - -// UART baudrate calc based on the bus and clockspeed -// NOTE: keep this in sync with the runtime/runtime_stm32f7x2.go clock init code -func (uart *UART) getBaudRateDivisor(baudRate uint32) uint32 { - var clock uint32 - switch uart.Bus { - case stm32.USART1, stm32.USART6: - clock = CPUFrequency() / 2 // APB2 Frequency - case stm32.USART2, stm32.USART3, stm32.UART4, stm32.UART5: - clock = CPUFrequency() / 8 // APB1 Frequency - } - return clock / baudRate -} - -// Register names vary by ST processor, these are for STM F7x2 -func (uart *UART) setRegisters() { - uart.rxReg = &uart.Bus.RDR - uart.txReg = &uart.Bus.TDR - uart.statusReg = &uart.Bus.ISR - uart.txEmptyFlag = stm32.USART_ISR_TXE -} - -//---------- I2C related code - -// Gets the value for TIMINGR register -func (i2c *I2C) getFreqRange(br uint32) uint32 { - // This is a 'magic' value calculated by STM32CubeMX - // for 27MHz PCLK1 (216MHz CPU Freq / 8). - // TODO: Do calculations based on PCLK1 - switch br { - case 10 * KHz: - return 0x5010C0FF - case 100 * KHz: - return 0x00606A9B - case 400 * KHz: - return 0x00201625 - case 500 * KHz: - return 0x00100429 - default: - return 0 - } -} diff --git a/emb/machine/machine_stm32l0.go b/emb/machine/machine_stm32l0.go deleted file mode 100644 index 1ecd958..0000000 --- a/emb/machine/machine_stm32l0.go +++ /dev/null @@ -1,317 +0,0 @@ -//go:build stm32l0 - -package machine - -// Peripheral abstraction layer for the stm32l0 - -import ( - "device/stm32" - "runtime/interrupt" -) - -func CPUFrequency() uint32 { - return 32000000 -} - -var deviceIDAddr = []uintptr{0x1FF80050, 0x1FF80054, 0x1FF80058} - -// Internal use: configured speed of the APB1 and APB2 timers, this should be kept -// in sync with any changes to runtime package which configures the oscillators -// and clock frequencies -const APB1_TIM_FREQ = 32e6 // 32MHz -const APB2_TIM_FREQ = 32e6 // 32MHz - -const ( - PA0 = portA + 0 - PA1 = portA + 1 - PA2 = portA + 2 - PA3 = portA + 3 - PA4 = portA + 4 - PA5 = portA + 5 - PA6 = portA + 6 - PA7 = portA + 7 - PA8 = portA + 8 - PA9 = portA + 9 - PA10 = portA + 10 - PA11 = portA + 11 - PA12 = portA + 12 - PA13 = portA + 13 - PA14 = portA + 14 - PA15 = portA + 15 - - PB0 = portB + 0 - PB1 = portB + 1 - PB2 = portB + 2 - PB3 = portB + 3 - PB4 = portB + 4 - PB5 = portB + 5 - PB6 = portB + 6 - PB7 = portB + 7 - PB8 = portB + 8 - PB9 = portB + 9 - PB10 = portB + 10 - PB11 = portB + 11 - PB12 = portB + 12 - PB13 = portB + 13 - PB14 = portB + 14 - PB15 = portB + 15 - - PC0 = portC + 0 - PC1 = portC + 1 - PC2 = portC + 2 - PC3 = portC + 3 - PC4 = portC + 4 - PC5 = portC + 5 - PC6 = portC + 6 - PC7 = portC + 7 - PC8 = portC + 8 - PC9 = portC + 9 - PC10 = portC + 10 - PC11 = portC + 11 - PC12 = portC + 12 - PC13 = portC + 13 - PC14 = portC + 14 - PC15 = portC + 15 - - PD0 = portD + 0 - PD1 = portD + 1 - PD2 = portD + 2 - PD3 = portD + 3 - PD4 = portD + 4 - PD5 = portD + 5 - PD6 = portD + 6 - PD7 = portD + 7 - PD8 = portD + 8 - PD9 = portD + 9 - PD10 = portD + 10 - PD11 = portD + 11 - PD12 = portD + 12 - PD13 = portD + 13 - PD14 = portD + 14 - PD15 = portD + 15 - - PE0 = portE + 0 - PE1 = portE + 1 - PE2 = portE + 2 - PE3 = portE + 3 - PE4 = portE + 4 - PE5 = portE + 5 - PE6 = portE + 6 - PE7 = portE + 7 - PE8 = portE + 8 - PE9 = portE + 9 - PE10 = portE + 10 - PE11 = portE + 11 - PE12 = portE + 12 - PE13 = portE + 13 - PE14 = portE + 14 - PE15 = portE + 15 - - PH0 = portH + 0 - PH1 = portH + 1 -) - -func (p Pin) getPort() *stm32.GPIO_Type { - switch p / 16 { - case 0: - return stm32.GPIOA - case 1: - return stm32.GPIOB - case 2: - return stm32.GPIOC - case 3: - return stm32.GPIOD - case 4: - return stm32.GPIOE - case 7: - return stm32.GPIOH - default: - panic("machine: unknown port") - } -} - -// enableClock enables the clock for this desired GPIO port. -func (p Pin) enableClock() { - switch p / 16 { - case 0: - stm32.RCC.IOPENR.SetBits(stm32.RCC_IOPENR_IOPAEN) - case 1: - stm32.RCC.IOPENR.SetBits(stm32.RCC_IOPENR_IOPBEN) - case 2: - stm32.RCC.IOPENR.SetBits(stm32.RCC_IOPENR_IOPCEN) - case 3: - stm32.RCC.IOPENR.SetBits(stm32.RCC_IOPENR_IOPDEN) - case 4: - stm32.RCC.IOPENR.SetBits(stm32.RCC_IOPENR_IOPEEN) - case 7: - stm32.RCC.IOPENR.SetBits(stm32.RCC_IOPENR_IOPHEN) - default: - panic("machine: unknown port") - } -} - -func (p Pin) registerInterrupt() interrupt.Interrupt { - pin := uint8(p) % 16 - - switch pin { - case 0: - return interrupt.New(stm32.IRQ_EXTI0_1, func(interrupt.Interrupt) { handlePinInterrupt(0) }) - case 1: - return interrupt.New(stm32.IRQ_EXTI0_1, func(interrupt.Interrupt) { handlePinInterrupt(1) }) - case 2: - return interrupt.New(stm32.IRQ_EXTI2_3, func(interrupt.Interrupt) { handlePinInterrupt(2) }) - case 3: - return interrupt.New(stm32.IRQ_EXTI2_3, func(interrupt.Interrupt) { handlePinInterrupt(3) }) - case 4: - return interrupt.New(stm32.IRQ_EXTI4_15, func(interrupt.Interrupt) { handlePinInterrupt(4) }) - case 5: - return interrupt.New(stm32.IRQ_EXTI4_15, func(interrupt.Interrupt) { handlePinInterrupt(5) }) - case 6: - return interrupt.New(stm32.IRQ_EXTI4_15, func(interrupt.Interrupt) { handlePinInterrupt(6) }) - case 7: - return interrupt.New(stm32.IRQ_EXTI4_15, func(interrupt.Interrupt) { handlePinInterrupt(7) }) - case 8: - return interrupt.New(stm32.IRQ_EXTI4_15, func(interrupt.Interrupt) { handlePinInterrupt(8) }) - case 9: - return interrupt.New(stm32.IRQ_EXTI4_15, func(interrupt.Interrupt) { handlePinInterrupt(9) }) - case 10: - return interrupt.New(stm32.IRQ_EXTI4_15, func(interrupt.Interrupt) { handlePinInterrupt(10) }) - case 11: - return interrupt.New(stm32.IRQ_EXTI4_15, func(interrupt.Interrupt) { handlePinInterrupt(11) }) - case 12: - return interrupt.New(stm32.IRQ_EXTI4_15, func(interrupt.Interrupt) { handlePinInterrupt(12) }) - case 13: - return interrupt.New(stm32.IRQ_EXTI4_15, func(interrupt.Interrupt) { handlePinInterrupt(13) }) - case 14: - return interrupt.New(stm32.IRQ_EXTI4_15, func(interrupt.Interrupt) { handlePinInterrupt(14) }) - case 15: - return interrupt.New(stm32.IRQ_EXTI4_15, func(interrupt.Interrupt) { handlePinInterrupt(15) }) - } - - return interrupt.Interrupt{} -} - -//---------- UART related types and code - -// Configure the UART. -func (uart *UART) configurePins(config UARTConfig) { - // enable the alternate functions on the TX and RX pins - config.TX.ConfigureAltFunc(PinConfig{Mode: PinModeUARTTX}, uart.TxAltFuncSelector) - config.RX.ConfigureAltFunc(PinConfig{Mode: PinModeUARTRX}, uart.RxAltFuncSelector) -} - -// UART baudrate calc based on the bus and clockspeed -func (uart *UART) getBaudRateDivisor(baudRate uint32) uint32 { - var clock, rate uint32 - switch uart.Bus { - case stm32.LPUART1: - clock = CPUFrequency() / 2 // APB1 Frequency - rate = uint32((256 * clock) / baudRate) - case stm32.USART1: - clock = CPUFrequency() / 2 // APB2 Frequency - rate = uint32(clock / baudRate) - case stm32.USART2: - clock = CPUFrequency() / 2 // APB1 Frequency - rate = uint32(clock / baudRate) - } - - return rate -} - -// Register names vary by ST processor, these are for STM L0 family -func (uart *UART) setRegisters() { - uart.rxReg = &uart.Bus.RDR - uart.txReg = &uart.Bus.TDR - uart.statusReg = &uart.Bus.ISR - uart.txEmptyFlag = stm32.USART_ISR_TXE -} - -//---------- SPI related types and code - -// SPI on the STM32Fxxx using MODER / alternate function pins -type SPI struct { - Bus *stm32.SPI_Type - AltFuncSelector uint8 -} - -func (spi *SPI) config8Bits() { - // no-op on this series -} - -// Set baud rate for SPI -func (spi *SPI) getBaudRate(config SPIConfig) uint32 { - var conf uint32 - - localFrequency := config.Frequency - - // Default - if config.Frequency == 0 { - config.Frequency = 4e6 - } - - if spi.Bus != stm32.SPI1 { - // Assume it's SPI2 or SPI3 on APB1 at 1/2 the clock frequency of APB2, so - // we want to pretend to request 2x the baudrate asked for - localFrequency = localFrequency * 2 - } - - // set frequency dependent on PCLK prescaler. Since these are rather weird - // speeds due to the CPU frequency, pick a range up to that frequency for - // clients to use more human-understandable numbers, e.g. nearest 100KHz - - // These are based on APB2 clock frequency (84MHz on the discovery board) - // TODO: also include the MCU/APB clock setting in the equation - switch { - case localFrequency < 328125: - conf = stm32.SPI_CR1_BR_Div256 - case localFrequency < 656250: - conf = stm32.SPI_CR1_BR_Div128 - case localFrequency < 1312500: - conf = stm32.SPI_CR1_BR_Div64 - case localFrequency < 2625000: - conf = stm32.SPI_CR1_BR_Div32 - case localFrequency < 5250000: - conf = stm32.SPI_CR1_BR_Div16 - case localFrequency < 10500000: - conf = stm32.SPI_CR1_BR_Div8 - // NOTE: many SPI components won't operate reliably (or at all) above 10MHz - // Check the datasheet of the part - case localFrequency < 21000000: - conf = stm32.SPI_CR1_BR_Div4 - case localFrequency < 42000000: - conf = stm32.SPI_CR1_BR_Div2 - default: - // None of the specific baudrates were selected; choose the lowest speed - conf = stm32.SPI_CR1_BR_Div256 - } - - return conf << stm32.SPI_CR1_BR_Pos -} - -// Configure SPI pins for input output and clock -func (spi *SPI) configurePins(config SPIConfig) { - config.SCK.ConfigureAltFunc(PinConfig{Mode: PinModeSPICLK}, spi.AltFuncSelector) - config.SDO.ConfigureAltFunc(PinConfig{Mode: PinModeSPISDO}, spi.AltFuncSelector) - config.SDI.ConfigureAltFunc(PinConfig{Mode: PinModeSPISDI}, spi.AltFuncSelector) -} - -//---------- I2C related types and code - -// Gets the value for TIMINGR register -func (i2c I2C) getFreqRange(br uint32) uint32 { - // This is a 'magic' value calculated by STM32CubeMX - // for 16MHz PCLK1. - // TODO: Do calculations based on PCLK1 - switch br { - case 10 * KHz: - return 0x40003EFF - case 100 * KHz: - return 0x00303D5B - case 400 * KHz: - return 0x0010061A - case 500 * KHz: - return 0x00000117 - default: - return 0 - } -} diff --git a/emb/machine/machine_stm32l0x1.go b/emb/machine/machine_stm32l0x1.go deleted file mode 100644 index f0d23ca..0000000 --- a/emb/machine/machine_stm32l0x1.go +++ /dev/null @@ -1,197 +0,0 @@ -//go:build stm32l0x1 - -package machine - -// Peripheral abstraction layer for the stm32l0 - -import ( - "device/stm32" - "runtime/interrupt" - "runtime/volatile" - "unsafe" -) - -const ( - AF0_SYSTEM_SPI1_USART2_LPTIM_TIM21 = 0 - AF1_SPI1_I2C1_LPTIM = 1 - AF2_LPTIM_TIM2 = 2 - AF3_I2C1 = 3 - AF4_I2C1_USART2_LPUART1_TIM22 = 4 - AF5_TIM2_21_22 = 5 - AF6_LPUART1 = 6 - AF7_COMP1_2 = 7 -) - -// Enable peripheral clock -func enableAltFuncClock(bus unsafe.Pointer) { - switch bus { - case unsafe.Pointer(stm32.PWR): // Power interface clock enable - stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_PWREN) - case unsafe.Pointer(stm32.I2C3): // I2C3 clock enable - stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_I2C3EN) - case unsafe.Pointer(stm32.I2C2): // I2C2 clock enable - stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_I2C2EN) - case unsafe.Pointer(stm32.I2C1): // I2C1 clock enable - stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_I2C1EN) - case unsafe.Pointer(stm32.USART5): // UART5 clock enable - stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_USART5EN) - case unsafe.Pointer(stm32.USART4): // UART4 clock enable - stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_USART4EN) - case unsafe.Pointer(stm32.USART2): // USART2 clock enable - stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_USART2EN) - case unsafe.Pointer(stm32.SPI2): // SPI2 clock enable - stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_SPI2EN) - case unsafe.Pointer(stm32.LPUART1): // LPUART1 clock enable - stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_LPUART1EN) - case unsafe.Pointer(stm32.WWDG): // Window watchdog clock enable - stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_WWDGEN) - case unsafe.Pointer(stm32.TIM7): // TIM7 clock enable - stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_TIM7EN) - case unsafe.Pointer(stm32.TIM6): // TIM6 clock enable - stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_TIM6EN) - case unsafe.Pointer(stm32.TIM3): // TIM3 clock enable - stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_TIM3EN) - case unsafe.Pointer(stm32.TIM2): // TIM2 clock enable - stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_TIM2EN) - case unsafe.Pointer(stm32.SYSCFG): // System configuration controller clock enable - stm32.RCC.APB2ENR.SetBits(stm32.RCC_APB2ENR_SYSCFGEN) - case unsafe.Pointer(stm32.SPI1): // SPI1 clock enable - stm32.RCC.APB2ENR.SetBits(stm32.RCC_APB2ENR_SPI1EN) - case unsafe.Pointer(stm32.ADC): // ADC clock enable - stm32.RCC.APB2ENR.SetBits(stm32.RCC_APB2ENR_ADCEN) - case unsafe.Pointer(stm32.USART1): // USART1 clock enable - stm32.RCC.APB2ENR.SetBits(stm32.RCC_APB2ENR_USART1EN) - } -} - -//---------- Timer related code - -var ( - TIM2 = TIM{ - EnableRegister: &stm32.RCC.APB1ENR, - EnableFlag: stm32.RCC_APB1ENR_TIM2EN, - Device: stm32.TIM2, - Channels: [4]TimerChannel{ - TimerChannel{Pins: []PinFunction{{PA0, AF2_LPTIM_TIM2}, {PA5, AF5_TIM2_21_22}, {PA8, AF5_TIM2_21_22}, {PA15, AF5_TIM2_21_22}}}, - TimerChannel{Pins: []PinFunction{{PA1, AF2_LPTIM_TIM2}, {PB3, AF2_LPTIM_TIM2}}}, - TimerChannel{Pins: []PinFunction{{PA2, AF2_LPTIM_TIM2}, {PB0, AF5_TIM2_21_22}, {PB10, AF2_LPTIM_TIM2}}}, - TimerChannel{Pins: []PinFunction{{PA3, AF2_LPTIM_TIM2}, {PB1, AF5_TIM2_21_22}, {PB11, AF2_LPTIM_TIM2}}}, - }, - busFreq: APB1_TIM_FREQ, - } - - TIM3 = TIM{ - EnableRegister: &stm32.RCC.APB1ENR, - EnableFlag: stm32.RCC_APB1ENR_TIM3EN, - Device: stm32.TIM3, - Channels: [4]TimerChannel{ - TimerChannel{Pins: []PinFunction{}}, - TimerChannel{Pins: []PinFunction{}}, - TimerChannel{Pins: []PinFunction{}}, - TimerChannel{Pins: []PinFunction{}}, - }, - busFreq: APB1_TIM_FREQ, - } - - TIM6 = TIM{ - EnableRegister: &stm32.RCC.APB1ENR, - EnableFlag: stm32.RCC_APB1ENR_TIM6EN, - Device: stm32.TIM6, - Channels: [4]TimerChannel{ - TimerChannel{Pins: []PinFunction{}}, - TimerChannel{Pins: []PinFunction{}}, - TimerChannel{Pins: []PinFunction{}}, - TimerChannel{Pins: []PinFunction{}}, - }, - busFreq: APB1_TIM_FREQ, - } - - TIM7 = TIM{ - EnableRegister: &stm32.RCC.APB1ENR, - EnableFlag: stm32.RCC_APB1ENR_TIM7EN, - Device: stm32.TIM7, - Channels: [4]TimerChannel{ - TimerChannel{Pins: []PinFunction{}}, - TimerChannel{Pins: []PinFunction{}}, - TimerChannel{Pins: []PinFunction{}}, - TimerChannel{Pins: []PinFunction{}}, - }, - busFreq: APB1_TIM_FREQ, - } - - TIM21 = TIM{ - EnableRegister: &stm32.RCC.APB2ENR, - EnableFlag: stm32.RCC_APB2ENR_TIM21EN, - Device: stm32.TIM21, - Channels: [4]TimerChannel{ - TimerChannel{Pins: []PinFunction{}}, - TimerChannel{Pins: []PinFunction{}}, - TimerChannel{Pins: []PinFunction{}}, - TimerChannel{Pins: []PinFunction{}}, - }, - busFreq: APB2_TIM_FREQ, - } - - TIM22 = TIM{ - EnableRegister: &stm32.RCC.APB2ENR, - EnableFlag: stm32.RCC_APB2ENR_TIM22EN, - Device: stm32.TIM2, - Channels: [4]TimerChannel{ - TimerChannel{Pins: []PinFunction{}}, - TimerChannel{Pins: []PinFunction{}}, - TimerChannel{Pins: []PinFunction{}}, - TimerChannel{Pins: []PinFunction{}}, - }, - busFreq: APB2_TIM_FREQ, - } -) - -func (t *TIM) registerUPInterrupt() interrupt.Interrupt { - switch t { - case &TIM2: - return interrupt.New(stm32.IRQ_TIM2, TIM2.handleUPInterrupt) - case &TIM3: - return interrupt.New(stm32.IRQ_TIM3, TIM3.handleUPInterrupt) - case &TIM6: - return interrupt.New(stm32.IRQ_TIM6, TIM6.handleUPInterrupt) - case &TIM7: - return interrupt.New(stm32.IRQ_TIM7, TIM7.handleUPInterrupt) - case &TIM21: - return interrupt.New(stm32.IRQ_TIM21, TIM21.handleUPInterrupt) - case &TIM22: - return interrupt.New(stm32.IRQ_TIM22, TIM22.handleUPInterrupt) - } - - return interrupt.Interrupt{} -} - -func (t *TIM) registerOCInterrupt() interrupt.Interrupt { - switch t { - case &TIM2: - return interrupt.New(stm32.IRQ_TIM2, TIM2.handleOCInterrupt) - case &TIM3: - return interrupt.New(stm32.IRQ_TIM3, TIM3.handleOCInterrupt) - case &TIM6: - return interrupt.New(stm32.IRQ_TIM6, TIM6.handleOCInterrupt) - case &TIM7: - return interrupt.New(stm32.IRQ_TIM7, TIM7.handleOCInterrupt) - case &TIM21: - return interrupt.New(stm32.IRQ_TIM21, TIM21.handleOCInterrupt) - case &TIM22: - return interrupt.New(stm32.IRQ_TIM22, TIM22.handleOCInterrupt) - } - - return interrupt.Interrupt{} -} - -func (t *TIM) enableMainOutput() { - // nothing to do - no BDTR register -} - -type arrtype = uint16 -type arrRegType = volatile.Register16 - -const ( - ARR_MAX = 0x10000 - PSC_MAX = 0x10000 -) diff --git a/emb/machine/machine_stm32l0x2.go b/emb/machine/machine_stm32l0x2.go deleted file mode 100644 index 2a74792..0000000 --- a/emb/machine/machine_stm32l0x2.go +++ /dev/null @@ -1,259 +0,0 @@ -//go:build stm32l0x2 - -package machine - -// Peripheral abstraction layer for the stm32l0 - -import ( - "device/stm32" - "runtime/interrupt" - "runtime/volatile" - "unsafe" -) - -const ( - AF0_SYSTEM_SPI1_2_I2S2_USART1_2_LPUART1_USB_LPTIM1_TSC_TIM2_21_22 = 0 - AF1_SPI1_2_I2S2_I2C1_TIM2_21 = 1 - AF2_SPI1_2_I2S2_LPUART1_USART5_USB_LPTIM1_TIM2_3 = 2 - AF3_I2C1_TSC = 3 - AF4_I2C1_USART1_2_LPUART1_TIM3_22 = 4 - AF5_SPI2_I2S2_I2C2_USART1_TIM2_21_22 = 5 - AF6_I2C1_2_LPUART1_USART4_5_TIM21 = 6 - AF7_I2C3_LPUART1_COMP1_2_TIM3 = 7 -) - -// Enable peripheral clock -func enableAltFuncClock(bus unsafe.Pointer) { - switch bus { - case unsafe.Pointer(stm32.DAC): // DAC interface clock enable - stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_DACEN) - case unsafe.Pointer(stm32.PWR): // Power interface clock enable - stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_PWREN) - case unsafe.Pointer(stm32.I2C3): // I2C3 clock enable - stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_I2C3EN) - case unsafe.Pointer(stm32.I2C2): // I2C2 clock enable - stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_I2C2EN) - case unsafe.Pointer(stm32.I2C1): // I2C1 clock enable - stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_I2C1EN) - case unsafe.Pointer(stm32.USART5): // UART5 clock enable - stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_USART5EN) - case unsafe.Pointer(stm32.USART4): // UART4 clock enable - stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_USART4EN) - case unsafe.Pointer(stm32.USART2): // USART2 clock enable - stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_USART2EN) - case unsafe.Pointer(stm32.SPI2): // SPI2 clock enable - stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_SPI2EN) - case unsafe.Pointer(stm32.LPUART1): // LPUART1 clock enable - stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_LPUART1EN) - case unsafe.Pointer(stm32.WWDG): // Window watchdog clock enable - stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_WWDGEN) - case unsafe.Pointer(stm32.TIM7): // TIM7 clock enable - stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_TIM7EN) - case unsafe.Pointer(stm32.TIM6): // TIM6 clock enable - stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_TIM6EN) - case unsafe.Pointer(stm32.TIM3): // TIM3 clock enable - stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_TIM3EN) - case unsafe.Pointer(stm32.TIM2): // TIM2 clock enable - stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_TIM2EN) - case unsafe.Pointer(stm32.SYSCFG): // System configuration controller clock enable - stm32.RCC.APB2ENR.SetBits(stm32.RCC_APB2ENR_SYSCFGEN) - case unsafe.Pointer(stm32.SPI1): // SPI1 clock enable - stm32.RCC.APB2ENR.SetBits(stm32.RCC_APB2ENR_SPI1EN) - case unsafe.Pointer(stm32.ADC): // ADC clock enable - stm32.RCC.APB2ENR.SetBits(stm32.RCC_APB2ENR_ADCEN) - case unsafe.Pointer(stm32.USART1): // USART1 clock enable - stm32.RCC.APB2ENR.SetBits(stm32.RCC_APB2ENR_USART1EN) - } -} - -//---------- Timer related code - -var ( - TIM2 = TIM{ - EnableRegister: &stm32.RCC.APB1ENR, - EnableFlag: stm32.RCC_APB1ENR_TIM2EN, - Device: stm32.TIM2, - Channels: [4]TimerChannel{ - TimerChannel{Pins: []PinFunction{ - {PA0, AF2_SPI1_2_I2S2_LPUART1_USART5_USB_LPTIM1_TIM2_3}, - {PA5, AF5_SPI2_I2S2_I2C2_USART1_TIM2_21_22}, - {PA15, AF5_SPI2_I2S2_I2C2_USART1_TIM2_21_22}, - {PE9, AF0_SYSTEM_SPI1_2_I2S2_USART1_2_LPUART1_USB_LPTIM1_TSC_TIM2_21_22}, - }}, - TimerChannel{Pins: []PinFunction{ - {PA1, AF2_SPI1_2_I2S2_LPUART1_USART5_USB_LPTIM1_TIM2_3}, - {PB3, AF2_SPI1_2_I2S2_LPUART1_USART5_USB_LPTIM1_TIM2_3}, - {PE10, AF0_SYSTEM_SPI1_2_I2S2_USART1_2_LPUART1_USB_LPTIM1_TSC_TIM2_21_22}, - }}, - TimerChannel{Pins: []PinFunction{ - {PA2, AF2_SPI1_2_I2S2_LPUART1_USART5_USB_LPTIM1_TIM2_3}, - {PB10, AF2_SPI1_2_I2S2_LPUART1_USART5_USB_LPTIM1_TIM2_3}, - {PE11, AF0_SYSTEM_SPI1_2_I2S2_USART1_2_LPUART1_USB_LPTIM1_TSC_TIM2_21_22}, - }}, - TimerChannel{Pins: []PinFunction{ - {PA3, AF2_SPI1_2_I2S2_LPUART1_USART5_USB_LPTIM1_TIM2_3}, - {PB11, AF2_SPI1_2_I2S2_LPUART1_USART5_USB_LPTIM1_TIM2_3}, - {PE12, AF0_SYSTEM_SPI1_2_I2S2_USART1_2_LPUART1_USB_LPTIM1_TSC_TIM2_21_22}, - }}, - }, - busFreq: APB1_TIM_FREQ, - } - - TIM3 = TIM{ - EnableRegister: &stm32.RCC.APB1ENR, - EnableFlag: stm32.RCC_APB1ENR_TIM3EN, - Device: stm32.TIM3, - Channels: [4]TimerChannel{ - TimerChannel{Pins: []PinFunction{ - {PA6, AF2_SPI1_2_I2S2_LPUART1_USART5_USB_LPTIM1_TIM2_3}, - {PB4, AF2_SPI1_2_I2S2_LPUART1_USART5_USB_LPTIM1_TIM2_3}, - {PC6, AF2_SPI1_2_I2S2_LPUART1_USART5_USB_LPTIM1_TIM2_3}, - {PE3, AF2_SPI1_2_I2S2_LPUART1_USART5_USB_LPTIM1_TIM2_3}, - }}, - TimerChannel{Pins: []PinFunction{ - {PA7, AF2_SPI1_2_I2S2_LPUART1_USART5_USB_LPTIM1_TIM2_3}, - {PB5, AF4_I2C1_USART1_2_LPUART1_TIM3_22}, - {PC7, AF2_SPI1_2_I2S2_LPUART1_USART5_USB_LPTIM1_TIM2_3}, - {PE4, AF2_SPI1_2_I2S2_LPUART1_USART5_USB_LPTIM1_TIM2_3}, - }}, - TimerChannel{Pins: []PinFunction{ - {PB0, AF2_SPI1_2_I2S2_LPUART1_USART5_USB_LPTIM1_TIM2_3}, - {PC8, AF2_SPI1_2_I2S2_LPUART1_USART5_USB_LPTIM1_TIM2_3}, - {PE5, AF2_SPI1_2_I2S2_LPUART1_USART5_USB_LPTIM1_TIM2_3}, - }}, - TimerChannel{Pins: []PinFunction{ - {PB1, AF2_SPI1_2_I2S2_LPUART1_USART5_USB_LPTIM1_TIM2_3}, - {PC9, AF2_SPI1_2_I2S2_LPUART1_USART5_USB_LPTIM1_TIM2_3}, - {PE6, AF2_SPI1_2_I2S2_LPUART1_USART5_USB_LPTIM1_TIM2_3}, - }}, - }, - busFreq: APB1_TIM_FREQ, - } - - TIM6 = TIM{ - EnableRegister: &stm32.RCC.APB1ENR, - EnableFlag: stm32.RCC_APB1ENR_TIM6EN, - Device: stm32.TIM6, - Channels: [4]TimerChannel{ - TimerChannel{Pins: []PinFunction{}}, - TimerChannel{Pins: []PinFunction{}}, - TimerChannel{Pins: []PinFunction{}}, - TimerChannel{Pins: []PinFunction{}}, - }, - busFreq: APB1_TIM_FREQ, - } - - TIM7 = TIM{ - EnableRegister: &stm32.RCC.APB1ENR, - EnableFlag: stm32.RCC_APB1ENR_TIM7EN, - Device: stm32.TIM7, - Channels: [4]TimerChannel{ - TimerChannel{Pins: []PinFunction{}}, - TimerChannel{Pins: []PinFunction{}}, - TimerChannel{Pins: []PinFunction{}}, - TimerChannel{Pins: []PinFunction{}}, - }, - busFreq: APB1_TIM_FREQ, - } - - TIM21 = TIM{ - EnableRegister: &stm32.RCC.APB2ENR, - EnableFlag: stm32.RCC_APB2ENR_TIM21EN, - Device: stm32.TIM21, - Channels: [4]TimerChannel{ - TimerChannel{Pins: []PinFunction{ - {PA2, AF0_SYSTEM_SPI1_2_I2S2_USART1_2_LPUART1_USB_LPTIM1_TSC_TIM2_21_22}, - {PB13, AF6_I2C1_2_LPUART1_USART4_5_TIM21}, - {PD0, AF0_SYSTEM_SPI1_2_I2S2_USART1_2_LPUART1_USB_LPTIM1_TSC_TIM2_21_22}, - {PE5, AF0_SYSTEM_SPI1_2_I2S2_USART1_2_LPUART1_USB_LPTIM1_TSC_TIM2_21_22}, - }}, - TimerChannel{Pins: []PinFunction{ - {PA3, AF0_SYSTEM_SPI1_2_I2S2_USART1_2_LPUART1_USB_LPTIM1_TSC_TIM2_21_22}, - {PB14, AF6_I2C1_2_LPUART1_USART4_5_TIM21}, - {PD7, AF1_SPI1_2_I2S2_I2C1_TIM2_21}, - {PE6, AF0_SYSTEM_SPI1_2_I2S2_USART1_2_LPUART1_USB_LPTIM1_TSC_TIM2_21_22}, - }}, - TimerChannel{Pins: []PinFunction{}}, - TimerChannel{Pins: []PinFunction{}}, - }, - busFreq: APB2_TIM_FREQ, - } - - TIM22 = TIM{ - EnableRegister: &stm32.RCC.APB2ENR, - EnableFlag: stm32.RCC_APB2ENR_TIM22EN, - Device: stm32.TIM2, - Channels: [4]TimerChannel{ - TimerChannel{Pins: []PinFunction{ - {PA6, AF5_SPI2_I2S2_I2C2_USART1_TIM2_21_22}, - {PB4, AF4_I2C1_USART1_2_LPUART1_TIM3_22}, - {PC6, AF0_SYSTEM_SPI1_2_I2S2_USART1_2_LPUART1_USB_LPTIM1_TSC_TIM2_21_22}, - {PE3, AF0_SYSTEM_SPI1_2_I2S2_USART1_2_LPUART1_USB_LPTIM1_TSC_TIM2_21_22}, - }}, - TimerChannel{Pins: []PinFunction{ - {PA7, AF5_SPI2_I2S2_I2C2_USART1_TIM2_21_22}, - {PB5, AF4_I2C1_USART1_2_LPUART1_TIM3_22}, - {PC7, AF0_SYSTEM_SPI1_2_I2S2_USART1_2_LPUART1_USB_LPTIM1_TSC_TIM2_21_22}, - {PE4, AF0_SYSTEM_SPI1_2_I2S2_USART1_2_LPUART1_USB_LPTIM1_TSC_TIM2_21_22}, - }}, - TimerChannel{Pins: []PinFunction{}}, - TimerChannel{Pins: []PinFunction{}}, - }, - busFreq: APB2_TIM_FREQ, - } -) - -func (t *TIM) registerUPInterrupt() interrupt.Interrupt { - switch t { - case &TIM2: - return interrupt.New(stm32.IRQ_TIM2, TIM2.handleUPInterrupt) - case &TIM3: - return interrupt.New(stm32.IRQ_TIM3, TIM3.handleUPInterrupt) - case &TIM6: - return interrupt.New(stm32.IRQ_TIM6_DAC, TIM6.handleUPInterrupt) - case &TIM7: - return interrupt.New(stm32.IRQ_TIM7, TIM7.handleUPInterrupt) - case &TIM21: - return interrupt.New(stm32.IRQ_TIM21, TIM21.handleUPInterrupt) - case &TIM22: - return interrupt.New(stm32.IRQ_TIM22, TIM22.handleUPInterrupt) - } - - return interrupt.Interrupt{} -} - -func (t *TIM) registerOCInterrupt() interrupt.Interrupt { - switch t { - case &TIM2: - return interrupt.New(stm32.IRQ_TIM2, TIM2.handleOCInterrupt) - case &TIM3: - return interrupt.New(stm32.IRQ_TIM3, TIM3.handleOCInterrupt) - case &TIM6: - return interrupt.New(stm32.IRQ_TIM6_DAC, TIM6.handleOCInterrupt) - case &TIM7: - return interrupt.New(stm32.IRQ_TIM7, TIM7.handleOCInterrupt) - case &TIM21: - return interrupt.New(stm32.IRQ_TIM21, TIM21.handleOCInterrupt) - case &TIM22: - return interrupt.New(stm32.IRQ_TIM22, TIM22.handleOCInterrupt) - } - - return interrupt.Interrupt{} -} - -func (t *TIM) enableMainOutput() { - // nothing to do - no BDTR register -} - -type arrtype = uint16 -type arrRegType = volatile.Register16 - -const ( - ARR_MAX = 0x10000 - PSC_MAX = 0x10000 -) - -func initRNG() { - stm32.RCC.AHBENR.SetBits(stm32.RCC_AHBENR_RNGEN) - stm32.RNG.CR.SetBits(stm32.RNG_CR_RNGEN) -} diff --git a/emb/machine/machine_stm32l4.go b/emb/machine/machine_stm32l4.go deleted file mode 100644 index b5babc0..0000000 --- a/emb/machine/machine_stm32l4.go +++ /dev/null @@ -1,650 +0,0 @@ -//go:build stm32l4 - -package machine - -import ( - "device/stm32" - "errors" - "internal/binary" - "runtime/interrupt" - "runtime/volatile" - "unsafe" -) - -// Peripheral abstraction layer for the stm32l4 - -var deviceIDAddr = []uintptr{0x1FFF7590, 0x1FFF7594, 0x1FFF7598} - -const ( - AF0_SYSTEM = 0 - AF1_TIM1_2_LPTIM1 = 1 - AF2_TIM1_2 = 2 - AF3_USART2 = 3 - AF4_I2C1_2_3 = 4 - AF5_SPI1_2 = 5 - AF6_SPI3 = 6 - AF7_USART1_2_3 = 7 - AF8_LPUART1 = 8 - AF9_CAN1_TSC = 9 - AF10_USB_QUADSPI = 10 - AF12_COMP1_2_SWPMI1 = 12 - AF13_SAI1 = 13 - AF14_TIM2_15_16_LPTIM2 = 14 - AF15_EVENTOUT = 15 -) - -const ( - PA0 = portA + 0 - PA1 = portA + 1 - PA2 = portA + 2 - PA3 = portA + 3 - PA4 = portA + 4 - PA5 = portA + 5 - PA6 = portA + 6 - PA7 = portA + 7 - PA8 = portA + 8 - PA9 = portA + 9 - PA10 = portA + 10 - PA11 = portA + 11 - PA12 = portA + 12 - PA13 = portA + 13 - PA14 = portA + 14 - PA15 = portA + 15 - - PB0 = portB + 0 - PB1 = portB + 1 - PB2 = portB + 2 - PB3 = portB + 3 - PB4 = portB + 4 - PB5 = portB + 5 - PB6 = portB + 6 - PB7 = portB + 7 - PB8 = portB + 8 - PB9 = portB + 9 - PB10 = portB + 10 - PB11 = portB + 11 - PB12 = portB + 12 - PB13 = portB + 13 - PB14 = portB + 14 - PB15 = portB + 15 - - PC0 = portC + 0 - PC1 = portC + 1 - PC2 = portC + 2 - PC3 = portC + 3 - PC4 = portC + 4 - PC5 = portC + 5 - PC6 = portC + 6 - PC7 = portC + 7 - PC8 = portC + 8 - PC9 = portC + 9 - PC10 = portC + 10 - PC11 = portC + 11 - PC12 = portC + 12 - PC13 = portC + 13 - PC14 = portC + 14 - PC15 = portC + 15 - - PD0 = portD + 0 - PD1 = portD + 1 - PD2 = portD + 2 - PD3 = portD + 3 - PD4 = portD + 4 - PD5 = portD + 5 - PD6 = portD + 6 - PD7 = portD + 7 - PD8 = portD + 8 - PD9 = portD + 9 - PD10 = portD + 10 - PD11 = portD + 11 - PD12 = portD + 12 - PD13 = portD + 13 - PD14 = portD + 14 - PD15 = portD + 15 - - PE0 = portE + 0 - PE1 = portE + 1 - PE2 = portE + 2 - PE3 = portE + 3 - PE4 = portE + 4 - PE5 = portE + 5 - PE6 = portE + 6 - PE7 = portE + 7 - PE8 = portE + 8 - PE9 = portE + 9 - PE10 = portE + 10 - PE11 = portE + 11 - PE12 = portE + 12 - PE13 = portE + 13 - PE14 = portE + 14 - PE15 = portE + 15 -) - -// IRQs are defined here as they vary in the SVDs, but do have consistent mapping -// to Timer Interrupts. -const ( - irq_TIM1_BRK_TIM15 = 24 - irq_TIM1_UP_TIM16 = 25 - irq_TIM1_TRG_COM_TIM17 = 26 - irq_TIM1_CC = 27 - irq_TIM2 = 28 - irq_TIM3 = 29 - irq_TIM4 = 30 - irq_TIM5 = 50 - irq_TIM6 = 54 - irq_TIM7 = 55 - irq_TIM8_BRK = 43 - irq_TIM8_UP = 44 - irq_TIM8_TRG_COM = 45 - irq_TIM8_CC = 46 -) - -func (p Pin) getPort() *stm32.GPIO_Type { - switch p / 16 { - case 0: - return stm32.GPIOA - case 1: - return stm32.GPIOB - case 2: - return stm32.GPIOC - case 3: - return stm32.GPIOD - case 4: - return stm32.GPIOE - default: - panic("machine: unknown port") - } -} - -// enableClock enables the clock for this desired GPIO port. -func (p Pin) enableClock() { - switch p / 16 { - case 0: - stm32.RCC.AHB2ENR.SetBits(stm32.RCC_AHB2ENR_GPIOAEN) - case 1: - stm32.RCC.AHB2ENR.SetBits(stm32.RCC_AHB2ENR_GPIOBEN) - case 2: - stm32.RCC.AHB2ENR.SetBits(stm32.RCC_AHB2ENR_GPIOCEN) - case 3: - stm32.RCC.AHB2ENR.SetBits(stm32.RCC_AHB2ENR_GPIODEN) - case 4: - stm32.RCC.AHB2ENR.SetBits(stm32.RCC_AHB2ENR_GPIOEEN) - default: - panic("machine: unknown port") - } -} - -// Enable peripheral clock -func enableAltFuncClock(bus unsafe.Pointer) { - switch bus { - case unsafe.Pointer(stm32.PWR): // Power interface clock enable - stm32.RCC.APB1ENR1.SetBits(stm32.RCC_APB1ENR1_PWREN) - case unsafe.Pointer(stm32.I2C3): // I2C3 clock enable - stm32.RCC.APB1ENR1.SetBits(stm32.RCC_APB1ENR1_I2C3EN) - case unsafe.Pointer(stm32.I2C2): // I2C2 clock enable - stm32.RCC.APB1ENR1.SetBits(stm32.RCC_APB1ENR1_I2C2EN) - case unsafe.Pointer(stm32.I2C1): // I2C1 clock enable - stm32.RCC.APB1ENR1.SetBits(stm32.RCC_APB1ENR1_I2C1EN) - case unsafe.Pointer(stm32.UART4): // UART4 clock enable - stm32.RCC.APB1ENR1.SetBits(stm32.RCC_APB1ENR1_UART4EN) - case unsafe.Pointer(stm32.USART3): // USART3 clock enable - stm32.RCC.APB1ENR1.SetBits(stm32.RCC_APB1ENR1_USART3EN) - case unsafe.Pointer(stm32.USART2): // USART2 clock enable - stm32.RCC.APB1ENR1.SetBits(stm32.RCC_APB1ENR1_USART2EN) - case unsafe.Pointer(stm32.SPI3): // SPI3 clock enable - stm32.RCC.APB1ENR1.SetBits(stm32.RCC_APB1ENR1_SPI3EN) - case unsafe.Pointer(stm32.SPI2): // SPI2 clock enable - stm32.RCC.APB1ENR1.SetBits(stm32.RCC_APB1ENR1_SPI2EN) - case unsafe.Pointer(stm32.WWDG): // Window watchdog clock enable - stm32.RCC.APB1ENR1.SetBits(stm32.RCC_APB1ENR1_WWDGEN) - case unsafe.Pointer(stm32.TIM7): // TIM7 clock enable - stm32.RCC.APB1ENR1.SetBits(stm32.RCC_APB1ENR1_TIM7EN) - case unsafe.Pointer(stm32.TIM6): // TIM6 clock enable - stm32.RCC.APB1ENR1.SetBits(stm32.RCC_APB1ENR1_TIM6EN) - case unsafe.Pointer(stm32.TIM3): // TIM3 clock enable - stm32.RCC.APB1ENR1.SetBits(stm32.RCC_APB1ENR1_TIM3EN) - case unsafe.Pointer(stm32.TIM2): // TIM2 clock enable - stm32.RCC.APB1ENR1.SetBits(stm32.RCC_APB1ENR1_TIM2EN) - case unsafe.Pointer(stm32.LPTIM2): // LPTIM2 clock enable - stm32.RCC.APB1ENR2.SetBits(stm32.RCC_APB1ENR2_LPTIM2EN) - case unsafe.Pointer(stm32.LPUART1): // LPUART1 clock enable - stm32.RCC.APB1ENR2.SetBits(stm32.RCC_APB1ENR2_LPUART1EN) - case unsafe.Pointer(stm32.TIM16): // TIM16 clock enable - stm32.RCC.APB2ENR.SetBits(stm32.RCC_APB2ENR_TIM16EN) - case unsafe.Pointer(stm32.TIM15): // TIM15 clock enable - stm32.RCC.APB2ENR.SetBits(stm32.RCC_APB2ENR_TIM15EN) - case unsafe.Pointer(stm32.SYSCFG): // System configuration controller clock enable - stm32.RCC.APB2ENR.SetBits(stm32.RCC_APB2ENR_SYSCFGEN) - case unsafe.Pointer(stm32.SPI1): // SPI1 clock enable - stm32.RCC.APB2ENR.SetBits(stm32.RCC_APB2ENR_SPI1EN) - case unsafe.Pointer(stm32.USART1): // USART1 clock enable - stm32.RCC.APB2ENR.SetBits(stm32.RCC_APB2ENR_USART1EN) - case unsafe.Pointer(stm32.TIM1): // TIM1 clock enable - stm32.RCC.APB2ENR.SetBits(stm32.RCC_APB2ENR_TIM1EN) - } -} - -func handlePinInterrupt(pin uint8) { - if stm32.EXTI.PR1.HasBits(1 << pin) { - // Writing 1 to the pending register clears the - // pending flag for that bit - stm32.EXTI.PR1.Set(1 << pin) - - callback := pinCallbacks[pin] - if callback != nil { - callback(interruptPins[pin]) - } - } -} - -func (p Pin) registerInterrupt() interrupt.Interrupt { - pin := uint8(p) % 16 - - switch pin { - case 0: - return interrupt.New(stm32.IRQ_EXTI0, func(interrupt.Interrupt) { handlePinInterrupt(0) }) - case 1: - return interrupt.New(stm32.IRQ_EXTI1, func(interrupt.Interrupt) { handlePinInterrupt(1) }) - case 2: - return interrupt.New(stm32.IRQ_EXTI2, func(interrupt.Interrupt) { handlePinInterrupt(2) }) - case 3: - return interrupt.New(stm32.IRQ_EXTI3, func(interrupt.Interrupt) { handlePinInterrupt(3) }) - case 4: - return interrupt.New(stm32.IRQ_EXTI4, func(interrupt.Interrupt) { handlePinInterrupt(4) }) - case 5: - return interrupt.New(stm32.IRQ_EXTI9_5, func(interrupt.Interrupt) { handlePinInterrupt(5) }) - case 6: - return interrupt.New(stm32.IRQ_EXTI9_5, func(interrupt.Interrupt) { handlePinInterrupt(6) }) - case 7: - return interrupt.New(stm32.IRQ_EXTI9_5, func(interrupt.Interrupt) { handlePinInterrupt(7) }) - case 8: - return interrupt.New(stm32.IRQ_EXTI9_5, func(interrupt.Interrupt) { handlePinInterrupt(8) }) - case 9: - return interrupt.New(stm32.IRQ_EXTI9_5, func(interrupt.Interrupt) { handlePinInterrupt(9) }) - case 10: - return interrupt.New(stm32.IRQ_EXTI15_10, func(interrupt.Interrupt) { handlePinInterrupt(10) }) - case 11: - return interrupt.New(stm32.IRQ_EXTI15_10, func(interrupt.Interrupt) { handlePinInterrupt(11) }) - case 12: - return interrupt.New(stm32.IRQ_EXTI15_10, func(interrupt.Interrupt) { handlePinInterrupt(12) }) - case 13: - return interrupt.New(stm32.IRQ_EXTI15_10, func(interrupt.Interrupt) { handlePinInterrupt(13) }) - case 14: - return interrupt.New(stm32.IRQ_EXTI15_10, func(interrupt.Interrupt) { handlePinInterrupt(14) }) - case 15: - return interrupt.New(stm32.IRQ_EXTI15_10, func(interrupt.Interrupt) { handlePinInterrupt(15) }) - } - - return interrupt.Interrupt{} -} - -//---------- UART related code - -// Configure the UART. -func (uart *UART) configurePins(config UARTConfig) { - // enable the alternate functions on the TX and RX pins - config.TX.ConfigureAltFunc(PinConfig{Mode: PinModeUARTTX}, uart.TxAltFuncSelector) - config.RX.ConfigureAltFunc(PinConfig{Mode: PinModeUARTRX}, uart.RxAltFuncSelector) -} - -// UART baudrate calc based on the bus and clockspeed -// NOTE: keep this in sync with the runtime/runtime_stm32l5x2.go clock init code -func (uart *UART) getBaudRateDivisor(baudRate uint32) uint32 { - return (CPUFrequency() / baudRate) -} - -// Register names vary by ST processor, these are for STM L5 -func (uart *UART) setRegisters() { - uart.rxReg = &uart.Bus.RDR - uart.txReg = &uart.Bus.TDR - uart.statusReg = &uart.Bus.ISR - uart.txEmptyFlag = stm32.USART_ISR_TXE -} - -//---------- SPI related types and code - -// SPI on the STM32Fxxx using MODER / alternate function pins -type SPI struct { - Bus *stm32.SPI_Type - AltFuncSelector uint8 -} - -func (spi *SPI) config8Bits() { - // Set rx threshold to 8-bits, so RXNE flag is set for 1 byte - // (common STM32 SPI implementation does 8-bit transfers only) - spi.Bus.CR2.SetBits(stm32.SPI_CR2_FRXTH) -} - -// Set baud rate for SPI -func (spi *SPI) getBaudRate(config SPIConfig) uint32 { - var conf uint32 - - // Default - if config.Frequency == 0 { - config.Frequency = 4e6 - } - - localFrequency := config.Frequency - - // set frequency dependent on PCLK prescaler. Since these are rather weird - // speeds due to the CPU frequency, pick a range up to that frequency for - // clients to use more human-understandable numbers, e.g. nearest 100KHz - - // These are based on 80MHz peripheral clock frequency - switch { - case localFrequency < 312500: - conf = stm32.SPI_CR1_BR_Div256 - case localFrequency < 625000: - conf = stm32.SPI_CR1_BR_Div128 - case localFrequency < 1250000: - conf = stm32.SPI_CR1_BR_Div64 - case localFrequency < 2500000: - conf = stm32.SPI_CR1_BR_Div32 - case localFrequency < 5000000: - conf = stm32.SPI_CR1_BR_Div16 - case localFrequency < 10000000: - conf = stm32.SPI_CR1_BR_Div8 - // NOTE: many SPI components won't operate reliably (or at all) above 10MHz - // Check the datasheet of the part - case localFrequency < 20000000: - conf = stm32.SPI_CR1_BR_Div4 - case localFrequency < 40000000: - conf = stm32.SPI_CR1_BR_Div2 - default: - // None of the specific baudrates were selected; choose the lowest speed - conf = stm32.SPI_CR1_BR_Div256 - } - - return conf << stm32.SPI_CR1_BR_Pos -} - -// Configure SPI pins for input output and clock -func (spi *SPI) configurePins(config SPIConfig) { - config.SCK.ConfigureAltFunc(PinConfig{Mode: PinModeSPICLK}, spi.AltFuncSelector) - config.SDO.ConfigureAltFunc(PinConfig{Mode: PinModeSPISDO}, spi.AltFuncSelector) - config.SDI.ConfigureAltFunc(PinConfig{Mode: PinModeSPISDI}, spi.AltFuncSelector) -} - -//---------- Timer related code - -var ( - TIM1 = TIM{ - EnableRegister: &stm32.RCC.APB2ENR, - EnableFlag: stm32.RCC_APB2ENR_TIM1EN, - Device: stm32.TIM1, - Channels: [4]TimerChannel{ - TimerChannel{Pins: []PinFunction{ - {PA8, AF1_TIM1_2_LPTIM1}, - }}, - TimerChannel{Pins: []PinFunction{ - {PA9, AF1_TIM1_2_LPTIM1}, - }}, - TimerChannel{Pins: []PinFunction{ - {PA10, AF1_TIM1_2_LPTIM1}, - }}, - TimerChannel{Pins: []PinFunction{ - {PA11, AF1_TIM1_2_LPTIM1}, - }}, - }, - busFreq: APB2_TIM_FREQ, - } - - TIM2 = TIM{ - EnableRegister: &stm32.RCC.APB1ENR1, - EnableFlag: stm32.RCC_APB1ENR1_TIM2EN, - Device: stm32.TIM2, - Channels: [4]TimerChannel{ - TimerChannel{Pins: []PinFunction{ - {PA0, AF1_TIM1_2_LPTIM1}, - {PA5, AF1_TIM1_2_LPTIM1}, - {PA15, AF1_TIM1_2_LPTIM1}, - }}, - TimerChannel{Pins: []PinFunction{ - {PA1, AF1_TIM1_2_LPTIM1}, - {PB3, AF1_TIM1_2_LPTIM1}, - }}, - TimerChannel{Pins: []PinFunction{ - {PA2, AF1_TIM1_2_LPTIM1}, - }}, - TimerChannel{Pins: []PinFunction{ - {PA3, AF1_TIM1_2_LPTIM1}, - }}, - }, - busFreq: APB1_TIM_FREQ, - } - - TIM3 = TIM{ - EnableRegister: &stm32.RCC.APB1ENR1, - EnableFlag: stm32.RCC_APB1ENR1_TIM3EN, - Device: stm32.TIM3, - Channels: [4]TimerChannel{ - TimerChannel{Pins: []PinFunction{}}, - TimerChannel{Pins: []PinFunction{}}, - TimerChannel{Pins: []PinFunction{}}, - TimerChannel{Pins: []PinFunction{}}, - }, - busFreq: APB1_TIM_FREQ, - } - - TIM6 = TIM{ - EnableRegister: &stm32.RCC.APB1ENR1, - EnableFlag: stm32.RCC_APB1ENR1_TIM6EN, - Device: stm32.TIM6, - Channels: [4]TimerChannel{ - TimerChannel{Pins: []PinFunction{}}, - TimerChannel{Pins: []PinFunction{}}, - TimerChannel{Pins: []PinFunction{}}, - TimerChannel{Pins: []PinFunction{}}, - }, - busFreq: APB1_TIM_FREQ, - } - - TIM7 = TIM{ - EnableRegister: &stm32.RCC.APB1ENR1, - EnableFlag: stm32.RCC_APB1ENR1_TIM7EN, - Device: stm32.TIM7, - Channels: [4]TimerChannel{ - TimerChannel{Pins: []PinFunction{}}, - TimerChannel{Pins: []PinFunction{}}, - TimerChannel{Pins: []PinFunction{}}, - TimerChannel{Pins: []PinFunction{}}, - }, - busFreq: APB1_TIM_FREQ, - } - - TIM15 = TIM{ - EnableRegister: &stm32.RCC.APB2ENR, - EnableFlag: stm32.RCC_APB2ENR_TIM15EN, - Device: stm32.TIM15, - Channels: [4]TimerChannel{ - TimerChannel{Pins: []PinFunction{ - {PA2, AF14_TIM2_15_16_LPTIM2}, - }}, - TimerChannel{Pins: []PinFunction{ - {PA3, AF14_TIM2_15_16_LPTIM2}, - }}, - TimerChannel{Pins: []PinFunction{}}, - TimerChannel{Pins: []PinFunction{}}, - }, - busFreq: APB2_TIM_FREQ, - } - - TIM16 = TIM{ - EnableRegister: &stm32.RCC.APB2ENR, - EnableFlag: stm32.RCC_APB2ENR_TIM16EN, - Device: stm32.TIM16, - Channels: [4]TimerChannel{ - TimerChannel{Pins: []PinFunction{ - {PA6, AF14_TIM2_15_16_LPTIM2}, - }}, - TimerChannel{Pins: []PinFunction{}}, - TimerChannel{Pins: []PinFunction{}}, - TimerChannel{Pins: []PinFunction{}}, - }, - busFreq: APB2_TIM_FREQ, - } -) - -func (t *TIM) registerUPInterrupt() interrupt.Interrupt { - switch t { - case &TIM1: - return interrupt.New(irq_TIM1_UP_TIM16, TIM1.handleUPInterrupt) - case &TIM2: - return interrupt.New(irq_TIM2, TIM2.handleUPInterrupt) - case &TIM3: - return interrupt.New(irq_TIM3, TIM3.handleUPInterrupt) - case &TIM6: - return interrupt.New(irq_TIM6, TIM6.handleUPInterrupt) - case &TIM7: - return interrupt.New(irq_TIM7, TIM7.handleUPInterrupt) - case &TIM15: - return interrupt.New(irq_TIM1_BRK_TIM15, TIM15.handleUPInterrupt) - case &TIM16: - return interrupt.New(irq_TIM1_UP_TIM16, TIM16.handleUPInterrupt) - } - - return interrupt.Interrupt{} -} - -func (t *TIM) registerOCInterrupt() interrupt.Interrupt { - switch t { - case &TIM1: - return interrupt.New(irq_TIM1_CC, TIM1.handleUPInterrupt) - case &TIM2: - return interrupt.New(irq_TIM2, TIM2.handleOCInterrupt) - case &TIM3: - return interrupt.New(irq_TIM3, TIM3.handleOCInterrupt) - case &TIM6: - return interrupt.New(irq_TIM6, TIM6.handleOCInterrupt) - case &TIM7: - return interrupt.New(irq_TIM7, TIM7.handleOCInterrupt) - case &TIM15: - return interrupt.New(irq_TIM1_BRK_TIM15, TIM15.handleOCInterrupt) - case &TIM16: - return interrupt.New(irq_TIM1_UP_TIM16, TIM16.handleOCInterrupt) - } - - return interrupt.Interrupt{} -} - -func (t *TIM) enableMainOutput() { - // nothing to do - no BDTR register -} - -type arrtype = uint32 -type arrRegType = volatile.Register32 - -const ( - ARR_MAX = 0x10000 - PSC_MAX = 0x10000 -) - -func initRNG() { - stm32.RCC.CRRCR.SetBits(stm32.RCC_CRRCR_HSI48ON) - for !stm32.RCC.CRRCR.HasBits(stm32.RCC_CRRCR_HSI48RDY) { - } - - stm32.RCC.AHB2ENR.SetBits(stm32.RCC_AHB2ENR_RNGEN) - stm32.RNG.CR.SetBits(stm32.RNG_CR_RNGEN) -} - -//---------- Flash related code - -const eraseBlockSizeValue = 2048 - -// see RM0394 page 83 -// eraseBlock of the passed in block number -func eraseBlock(block uint32) error { - waitUntilFlashDone() - - // clear any previous errors - stm32.FLASH.SR.SetBits(0x3FA) - - // page erase operation - stm32.FLASH.SetCR_PER(1) - defer stm32.FLASH.SetCR_PER(0) - - // set the page to be erased - stm32.FLASH.SetCR_PNB(block) - - // start the page erase - stm32.FLASH.SetCR_START(1) - - waitUntilFlashDone() - - if err := checkError(); err != nil { - return err - } - - return nil -} - -const writeBlockSize = 8 - -// see RM0394 page 84 -// It is only possible to program double word (2 x 32-bit data). -func writeFlashData(address uintptr, data []byte) (int, error) { - if len(data)%writeBlockSize != 0 { - return 0, errFlashInvalidWriteLength - } - - waitUntilFlashDone() - - // clear any previous errors - stm32.FLASH.SR.SetBits(0x3FA) - - for j := 0; j < len(data); j += writeBlockSize { - // start page write operation - stm32.FLASH.SetCR_PG(1) - - // write second word using double-word high order word - *(*uint32)(unsafe.Pointer(address)) = binary.LittleEndian.Uint32(data[j : j+writeBlockSize/2]) - - address += writeBlockSize / 2 - - // write first word using double-word low order word - *(*uint32)(unsafe.Pointer(address)) = binary.LittleEndian.Uint32(data[j+writeBlockSize/2 : j+writeBlockSize]) - - waitUntilFlashDone() - - if err := checkError(); err != nil { - return j, err - } - - // end flash write - stm32.FLASH.SetCR_PG(0) - address += writeBlockSize / 2 - } - - return len(data), nil -} - -func waitUntilFlashDone() { - for stm32.FLASH.GetSR_BSY() != 0 { - } -} - -var ( - errFlashPGS = errors.New("errFlashPGS") - errFlashSIZE = errors.New("errFlashSIZE") - errFlashPGA = errors.New("errFlashPGA") - errFlashWRP = errors.New("errFlashWRP") - errFlashPROG = errors.New("errFlashPROG") -) - -func checkError() error { - switch { - case stm32.FLASH.GetSR_PGSERR() != 0: - return errFlashPGS - case stm32.FLASH.GetSR_SIZERR() != 0: - return errFlashSIZE - case stm32.FLASH.GetSR_PGAERR() != 0: - return errFlashPGA - case stm32.FLASH.GetSR_WRPERR() != 0: - return errFlashWRP - case stm32.FLASH.GetSR_PROGERR() != 0: - return errFlashPROG - } - - return nil -} diff --git a/emb/machine/machine_stm32l4x2.go b/emb/machine/machine_stm32l4x2.go deleted file mode 100644 index 142a8f5..0000000 --- a/emb/machine/machine_stm32l4x2.go +++ /dev/null @@ -1,36 +0,0 @@ -//go:build stm32l4x2 - -package machine - -// Peripheral abstraction layer for the stm32l4x2 - -func CPUFrequency() uint32 { - return 80000000 -} - -// Internal use: configured speed of the APB1 and APB2 timers, this should be kept -// in sync with any changes to runtime package which configures the oscillators -// and clock frequencies -const APB1_TIM_FREQ = 80e6 // 80MHz -const APB2_TIM_FREQ = 80e6 // 80MHz - -//---------- I2C related code - -// Gets the value for TIMINGR register -func (i2c *I2C) getFreqRange(br uint32) uint32 { - // These are 'magic' values calculated by STM32CubeMX - // for 80MHz PCLK1. - // TODO: Do calculations based on PCLK1 - switch br { - case 10 * KHz: - return 0xF010F3FE - case 100 * KHz: - return 0x10909CEC - case 400 * KHz: - return 0x00702991 - case 500 * KHz: - return 0x00300E84 - default: - return 0 - } -} diff --git a/emb/machine/machine_stm32l4x5.go b/emb/machine/machine_stm32l4x5.go deleted file mode 100644 index c8c550c..0000000 --- a/emb/machine/machine_stm32l4x5.go +++ /dev/null @@ -1,36 +0,0 @@ -//go:build stm32l4x5 - -package machine - -// Peripheral abstraction layer for the stm32l4x5 - -func CPUFrequency() uint32 { - return 120e6 -} - -// Internal use: configured speed of the APB1 and APB2 timers, this should be kept -// in sync with any changes to runtime package which configures the oscillators -// and clock frequencies -const APB1_TIM_FREQ = 120e6 // 120MHz -const APB2_TIM_FREQ = 120e6 // 120MHz - -//---------- I2C related code - -// Gets the value for TIMINGR register -func (i2c *I2C) getFreqRange(br uint32) uint32 { - // This is a 'magic' value calculated by STM32CubeMX - // for 120MHz PCLK1. - // TODO: Do calculations based on PCLK1 - switch br { - case 10 * KHz: - return 0x0 // does this even work? zero is weird here. - case 100 * KHz: - return 0x307075B1 - case 400 * KHz: - return 0x00B03FDB - case 500 * KHz: - return 0x005017C7 - default: - return 0 - } -} diff --git a/emb/machine/machine_stm32l4x6.go b/emb/machine/machine_stm32l4x6.go deleted file mode 100644 index de878eb..0000000 --- a/emb/machine/machine_stm32l4x6.go +++ /dev/null @@ -1,36 +0,0 @@ -//go:build stm32l4x6 - -package machine - -// Peripheral abstraction layer for the stm32l4x6 - -func CPUFrequency() uint32 { - return 80e6 -} - -// Internal use: configured speed of the APB1 and APB2 timers, this should be kept -// in sync with any changes to runtime package which configures the oscillators -// and clock frequencies -const APB1_TIM_FREQ = 80e6 // 80MHz -const APB2_TIM_FREQ = 80e6 // 80MHz - -//---------- I2C related code - -// Gets the value for TIMINGR register -func (i2c *I2C) getFreqRange(br uint32) uint32 { - // This is a 'magic' value calculated by STM32CubeMX - // for 80MHz PCLK1. - // TODO: Do calculations based on PCLK1 - switch br { - case 10 * KHz: - return 0xF010F3FE - case 100 * KHz: - return 0x10909CEC - case 400 * KHz: - return 0x00702991 - case 500 * KHz: - return 0x00300E84 - default: - return 0 - } -} diff --git a/emb/machine/machine_stm32l5.go b/emb/machine/machine_stm32l5.go deleted file mode 100644 index faa583c..0000000 --- a/emb/machine/machine_stm32l5.go +++ /dev/null @@ -1,559 +0,0 @@ -//go:build stm32l5 - -package machine - -// Peripheral abstraction layer for the stm32l5 - -import ( - "device/stm32" - "runtime/interrupt" - "runtime/volatile" - "unsafe" -) - -var deviceIDAddr = []uintptr{0x0BFA0590, 0x0BFA0594, 0x0BFA0598} - -const ( - AF0_SYSTEM = 0 - AF1_TIM1_2_5_8_LPTIM1 = 1 - AF2_TIM1_2_3_4_5_LPTIM3 = 2 - AF3_SPI2_SAI1_I2C4_USART2_TIM1_8_OCTOSPI1 = 3 - AF4_I2C1_2_3_4 = 4 - AF5_SPI1_2_3_I2C4_DFSDM1_OCTOSPI1 = 5 - AF6_SPI3_I2C3_DFSDM1_COMP1 = 6 - AF7_USART1_2_3 = 7 - AF8_UART4_5_LPUART1_SDMMC1 = 8 - AF9_FDCAN1_TSC = 9 - AF10_USB_OCTOSPI1 = 10 - AF11_UCPD1 = 11 - AF12_SDMMC1_COMP1_2_TIM1_8_FMC = 12 - AF13_SAI1_2_TIM8 = 13 - AF14_TIM2_8_15_16_17_LPTIM2 = 14 - AF15_EVENTOUT = 15 -) - -const ( - PA0 = portA + 0 - PA1 = portA + 1 - PA2 = portA + 2 - PA3 = portA + 3 - PA4 = portA + 4 - PA5 = portA + 5 - PA6 = portA + 6 - PA7 = portA + 7 - PA8 = portA + 8 - PA9 = portA + 9 - PA10 = portA + 10 - PA11 = portA + 11 - PA12 = portA + 12 - PA13 = portA + 13 - PA14 = portA + 14 - PA15 = portA + 15 - - PB0 = portB + 0 - PB1 = portB + 1 - PB2 = portB + 2 - PB3 = portB + 3 - PB4 = portB + 4 - PB5 = portB + 5 - PB6 = portB + 6 - PB7 = portB + 7 - PB8 = portB + 8 - PB9 = portB + 9 - PB10 = portB + 10 - PB11 = portB + 11 - PB12 = portB + 12 - PB13 = portB + 13 - PB14 = portB + 14 - PB15 = portB + 15 - - PC0 = portC + 0 - PC1 = portC + 1 - PC2 = portC + 2 - PC3 = portC + 3 - PC4 = portC + 4 - PC5 = portC + 5 - PC6 = portC + 6 - PC7 = portC + 7 - PC8 = portC + 8 - PC9 = portC + 9 - PC10 = portC + 10 - PC11 = portC + 11 - PC12 = portC + 12 - PC13 = portC + 13 - PC14 = portC + 14 - PC15 = portC + 15 - - PD0 = portD + 0 - PD1 = portD + 1 - PD2 = portD + 2 - PD3 = portD + 3 - PD4 = portD + 4 - PD5 = portD + 5 - PD6 = portD + 6 - PD7 = portD + 7 - PD8 = portD + 8 - PD9 = portD + 9 - PD10 = portD + 10 - PD11 = portD + 11 - PD12 = portD + 12 - PD13 = portD + 13 - PD14 = portD + 14 - PD15 = portD + 15 - - PE0 = portE + 0 - PE1 = portE + 1 - PE2 = portE + 2 - PE3 = portE + 3 - PE4 = portE + 4 - PE5 = portE + 5 - PE6 = portE + 6 - PE7 = portE + 7 - PE8 = portE + 8 - PE9 = portE + 9 - PE10 = portE + 10 - PE11 = portE + 11 - PE12 = portE + 12 - PE13 = portE + 13 - PE14 = portE + 14 - PE15 = portE + 15 - - PF0 = portF + 0 - PF1 = portF + 1 - PF2 = portF + 2 - PF3 = portF + 3 - PF4 = portF + 4 - PF5 = portF + 5 - PF6 = portF + 6 - PF7 = portF + 7 - PF8 = portF + 8 - PF9 = portF + 9 - PF10 = portF + 10 - PF11 = portF + 11 - PF12 = portF + 12 - PF13 = portF + 13 - PF14 = portF + 14 - PF15 = portF + 15 - - PG0 = portG + 0 - PG1 = portG + 1 - PG2 = portG + 2 - PG3 = portG + 3 - PG4 = portG + 4 - PG5 = portG + 5 - PG6 = portG + 6 - PG7 = portG + 7 - PG8 = portG + 8 - PG9 = portG + 9 - PG10 = portG + 10 - PG11 = portG + 11 - PG12 = portG + 12 - PG13 = portG + 13 - PG14 = portG + 14 - PG15 = portG + 15 - - PH0 = portH + 0 - PH1 = portH + 1 -) - -func (p Pin) getPort() *stm32.GPIO_Type { - switch p / 16 { - case 0: - return stm32.GPIOA - case 1: - return stm32.GPIOB - case 2: - return stm32.GPIOC - case 3: - return stm32.GPIOD - case 4: - return stm32.GPIOE - case 5: - return stm32.GPIOF - case 6: - return stm32.GPIOG - case 7: - return stm32.GPIOH - default: - panic("machine: unknown port") - } -} - -// enableClock enables the clock for this desired GPIO port. -func (p Pin) enableClock() { - switch p / 16 { - case 0: - stm32.RCC.AHB2ENR.SetBits(stm32.RCC_AHB2ENR_GPIOAEN) - case 1: - stm32.RCC.AHB2ENR.SetBits(stm32.RCC_AHB2ENR_GPIOBEN) - case 2: - stm32.RCC.AHB2ENR.SetBits(stm32.RCC_AHB2ENR_GPIOCEN) - case 3: - stm32.RCC.AHB2ENR.SetBits(stm32.RCC_AHB2ENR_GPIODEN) - case 4: - stm32.RCC.AHB2ENR.SetBits(stm32.RCC_AHB2ENR_GPIOEEN) - case 5: - stm32.RCC.AHB2ENR.SetBits(stm32.RCC_AHB2ENR_GPIOFEN) - case 6: - stm32.RCC.AHB2ENR.SetBits(stm32.RCC_AHB2ENR_GPIOGEN) - case 7: - stm32.RCC.AHB2ENR.SetBits(stm32.RCC_AHB2ENR_GPIOHEN) - default: - panic("machine: unknown port") - } -} - -// Enable peripheral clock -func enableAltFuncClock(bus unsafe.Pointer) { - switch bus { - case unsafe.Pointer(stm32.DAC): // DAC interface clock enable - stm32.RCC.APB1ENR1.SetBits(stm32.RCC_APB1ENR1_DAC1EN) - case unsafe.Pointer(stm32.PWR): // Power interface clock enable - stm32.RCC.APB1ENR1.SetBits(stm32.RCC_APB1ENR1_PWREN) - case unsafe.Pointer(stm32.I2C3): // I2C3 clock enable - stm32.RCC.APB1ENR1.SetBits(stm32.RCC_APB1ENR1_I2C3EN) - case unsafe.Pointer(stm32.I2C2): // I2C2 clock enable - stm32.RCC.APB1ENR1.SetBits(stm32.RCC_APB1ENR1_I2C2EN) - case unsafe.Pointer(stm32.I2C1): // I2C1 clock enable - stm32.RCC.APB1ENR1.SetBits(stm32.RCC_APB1ENR1_I2C1EN) - case unsafe.Pointer(stm32.UART5): // UART5 clock enable - stm32.RCC.APB1ENR1.SetBits(stm32.RCC_APB1ENR1_UART5EN) - case unsafe.Pointer(stm32.UART4): // UART4 clock enable - stm32.RCC.APB1ENR1.SetBits(stm32.RCC_APB1ENR1_UART4EN) - case unsafe.Pointer(stm32.USART3): // USART3 clock enable - stm32.RCC.APB1ENR1.SetBits(stm32.RCC_APB1ENR1_USART3EN) - case unsafe.Pointer(stm32.USART2): // USART2 clock enable - stm32.RCC.APB1ENR1.SetBits(stm32.RCC_APB1ENR1_USART2EN) - case unsafe.Pointer(stm32.SPI3): // SPI3 clock enable - stm32.RCC.APB1ENR1.SetBits(stm32.RCC_APB1ENR1_SP3EN) - case unsafe.Pointer(stm32.SPI2): // SPI2 clock enable - stm32.RCC.APB1ENR1.SetBits(stm32.RCC_APB1ENR1_SPI2EN) - case unsafe.Pointer(stm32.WWDG): // Window watchdog clock enable - stm32.RCC.APB1ENR1.SetBits(stm32.RCC_APB1ENR1_WWDGEN) - case unsafe.Pointer(stm32.TIM7): // TIM7 clock enable - stm32.RCC.APB1ENR1.SetBits(stm32.RCC_APB1ENR1_TIM7EN) - case unsafe.Pointer(stm32.TIM6): // TIM6 clock enable - stm32.RCC.APB1ENR1.SetBits(stm32.RCC_APB1ENR1_TIM6EN) - case unsafe.Pointer(stm32.TIM5): // TIM5 clock enable - stm32.RCC.APB1ENR1.SetBits(stm32.RCC_APB1ENR1_TIM5EN) - case unsafe.Pointer(stm32.TIM4): // TIM4 clock enable - stm32.RCC.APB1ENR1.SetBits(stm32.RCC_APB1ENR1_TIM4EN) - case unsafe.Pointer(stm32.TIM3): // TIM3 clock enable - stm32.RCC.APB1ENR1.SetBits(stm32.RCC_APB1ENR1_TIM3EN) - case unsafe.Pointer(stm32.TIM2): // TIM2 clock enable - stm32.RCC.APB1ENR1.SetBits(stm32.RCC_APB1ENR1_TIM2EN) - case unsafe.Pointer(stm32.UCPD1): // UCPD1 clock enable - stm32.RCC.APB1ENR2.SetBits(stm32.RCC_APB1ENR2_UCPD1EN) - case unsafe.Pointer(stm32.FDCAN1): // FDCAN1 clock enable - stm32.RCC.APB1ENR2.SetBits(stm32.RCC_APB1ENR2_FDCAN1EN) - case unsafe.Pointer(stm32.LPTIM3): // LPTIM3 clock enable - stm32.RCC.APB1ENR2.SetBits(stm32.RCC_APB1ENR2_LPTIM3EN) - case unsafe.Pointer(stm32.LPTIM2): // LPTIM2 clock enable - stm32.RCC.APB1ENR2.SetBits(stm32.RCC_APB1ENR2_LPTIM2EN) - case unsafe.Pointer(stm32.I2C4): // I2C4 clock enable - stm32.RCC.APB1ENR2.SetBits(stm32.RCC_APB1ENR2_I2C4EN) - case unsafe.Pointer(stm32.LPUART1): // LPUART1 clock enable - stm32.RCC.APB1ENR2.SetBits(stm32.RCC_APB1ENR2_LPUART1EN) - case unsafe.Pointer(stm32.TIM17): // TIM17 clock enable - stm32.RCC.APB2ENR.SetBits(stm32.RCC_APB2ENR_TIM17EN) - case unsafe.Pointer(stm32.TIM16): // TIM16 clock enable - stm32.RCC.APB2ENR.SetBits(stm32.RCC_APB2ENR_TIM16EN) - case unsafe.Pointer(stm32.TIM15): // TIM15 clock enable - stm32.RCC.APB2ENR.SetBits(stm32.RCC_APB2ENR_TIM15EN) - case unsafe.Pointer(stm32.SYSCFG): // System configuration controller clock enable - stm32.RCC.APB2ENR.SetBits(stm32.RCC_APB2ENR_SYSCFGEN) - case unsafe.Pointer(stm32.SPI1): // SPI1 clock enable - stm32.RCC.APB2ENR.SetBits(stm32.RCC_APB2ENR_SPI1EN) - case unsafe.Pointer(stm32.USART1): // USART1 clock enable - stm32.RCC.APB2ENR.SetBits(stm32.RCC_APB2ENR_USART1EN) - case unsafe.Pointer(stm32.TIM8): // TIM8 clock enable - stm32.RCC.APB2ENR.SetBits(stm32.RCC_APB2ENR_TIM8EN) - case unsafe.Pointer(stm32.TIM1): // TIM1 clock enable - stm32.RCC.APB2ENR.SetBits(stm32.RCC_APB2ENR_TIM1EN) - } -} - -func (p Pin) registerInterrupt() interrupt.Interrupt { - pin := uint8(p) % 16 - - switch pin { - case 0: - return interrupt.New(stm32.IRQ_EXTI0, func(interrupt.Interrupt) { handlePinInterrupt(0) }) - case 1: - return interrupt.New(stm32.IRQ_EXTI1, func(interrupt.Interrupt) { handlePinInterrupt(1) }) - case 2: - return interrupt.New(stm32.IRQ_EXTI2, func(interrupt.Interrupt) { handlePinInterrupt(2) }) - case 3: - return interrupt.New(stm32.IRQ_EXTI3, func(interrupt.Interrupt) { handlePinInterrupt(3) }) - case 4: - return interrupt.New(stm32.IRQ_EXTI4, func(interrupt.Interrupt) { handlePinInterrupt(4) }) - case 5: - return interrupt.New(stm32.IRQ_EXTI5, func(interrupt.Interrupt) { handlePinInterrupt(5) }) - case 6: - return interrupt.New(stm32.IRQ_EXTI6, func(interrupt.Interrupt) { handlePinInterrupt(6) }) - case 7: - return interrupt.New(stm32.IRQ_EXTI7, func(interrupt.Interrupt) { handlePinInterrupt(7) }) - case 8: - return interrupt.New(stm32.IRQ_EXTI8, func(interrupt.Interrupt) { handlePinInterrupt(8) }) - case 9: - return interrupt.New(stm32.IRQ_EXTI9, func(interrupt.Interrupt) { handlePinInterrupt(9) }) - case 10: - return interrupt.New(stm32.IRQ_EXTI10, func(interrupt.Interrupt) { handlePinInterrupt(10) }) - case 11: - return interrupt.New(stm32.IRQ_EXTI11, func(interrupt.Interrupt) { handlePinInterrupt(11) }) - case 12: - return interrupt.New(stm32.IRQ_EXTI12, func(interrupt.Interrupt) { handlePinInterrupt(12) }) - case 13: - return interrupt.New(stm32.IRQ_EXTI13, func(interrupt.Interrupt) { handlePinInterrupt(13) }) - case 14: - return interrupt.New(stm32.IRQ_EXTI14, func(interrupt.Interrupt) { handlePinInterrupt(14) }) - case 15: - return interrupt.New(stm32.IRQ_EXTI15, func(interrupt.Interrupt) { handlePinInterrupt(15) }) - } - - return interrupt.Interrupt{} -} - -func handlePinInterrupt(pin uint8) { - // The pin abstraction doesn't differentiate pull-up - // events from pull-down events, so combine them to - // a single call here. - - if stm32.EXTI.RPR1.HasBits(1< clock { - freq = clock - } - - // calculate the exact clock divisor (freq=clock/div -> div=clock/freq). - // truncation is fine, since it produces a less-than-or-equal divisor, and - // thus a greater-than-or-equal frequency. - // divisors only come in consecutive powers of 2, so we can use log2 (or, - // equivalently, bits.Len - 1) to convert to respective enum value. - div := bits.Len32(clock/freq) - 1 - - // but DIV1 (2^0) is not permitted, as the least divisor is DIV2 (2^1), so - // subtract 1 from the log2 value, keeping a lower bound of 0 - if div < 0 { - div = 0 - } else if div > 0 { - div-- - } - - // finally, shift the enumerated value into position for SPI CR1 - return uint32(div) << stm32.SPI_CR1_BR_Pos -} - -//---------- I2C related code - -// Gets the value for TIMINGR register -func (i2c *I2C) getFreqRange(br uint32) uint32 { - // This is a 'magic' value calculated by STM32CubeMX - // for 48Mhz PCLK1. - // TODO: Do calculations based on PCLK1 - switch br { - case 10 * KHz: - return 0x9010DEFF - case 100 * KHz: - return 0x20303E5D - case 400 * KHz: - return 0x2010091A - case 500 * KHz: - return 0x00201441 - default: - return 0 - } -} - -//---------- UART related code - -// Configure the UART. -func (uart UART) configurePins(config UARTConfig) { - // enable the alternate functions on the TX and RX pins - config.TX.ConfigureAltFunc(PinConfig{Mode: PinModeUARTTX}, uart.TxAltFuncSelector) - config.RX.ConfigureAltFunc(PinConfig{Mode: PinModeUARTRX}, uart.RxAltFuncSelector) -} - -// UART baudrate calc based on the bus and clockspeed -// NOTE: keep this in sync with the runtime/runtime_stm32wle5.go clock init code -func (uart *UART) getBaudRateDivisor(baudRate uint32) uint32 { - var br uint32 - uartClock := CPUFrequency() // No Prescaler configuration - br = uint32((uartClock + baudRate/2) / baudRate) - return (br) -} - -// Register names vary by ST processor, these are for STM L5 -func (uart *UART) setRegisters() { - uart.rxReg = &uart.Bus.RDR - uart.txReg = &uart.Bus.TDR - uart.statusReg = &uart.Bus.ISR - uart.txEmptyFlag = stm32.USART_ISR_TXFNF //(TXFNF == TXE == bit 7, but depends alternate RM0461/1094) -} - -//---------- Timer related code - -var ( - TIM1 = TIM{ - EnableRegister: &stm32.RCC.APB2ENR, - EnableFlag: stm32.RCC_APB2ENR_TIM1EN, - Device: stm32.TIM1, - Channels: [4]TimerChannel{ - TimerChannel{Pins: []PinFunction{{PA8, AF1_TIM1_2_LPTIM1}}}, - TimerChannel{Pins: []PinFunction{{PA9, AF1_TIM1_2_LPTIM1}}}, - TimerChannel{Pins: []PinFunction{{PA10, AF1_TIM1_2_LPTIM1}}}, - TimerChannel{Pins: []PinFunction{{PA11, AF1_TIM1_2_LPTIM1}}}, - }, - busFreq: APB2_TIM_FREQ, - } - TIM2 = TIM{ - EnableRegister: &stm32.RCC.APB1ENR1, - EnableFlag: stm32.RCC_APB1ENR1_TIM2EN, - Device: stm32.TIM2, - Channels: [4]TimerChannel{ - TimerChannel{Pins: []PinFunction{{PA0, AF1_TIM1_2_LPTIM1}, {PA5, AF1_TIM1_2_LPTIM1}, {PA15, AF1_TIM1_2_LPTIM1}}}, - TimerChannel{Pins: []PinFunction{{PA1, AF1_TIM1_2_LPTIM1}, {PB3, AF1_TIM1_2_LPTIM1}}}, - TimerChannel{Pins: []PinFunction{{PA2, AF1_TIM1_2_LPTIM1}, {PB10, AF1_TIM1_2_LPTIM1}}}, - TimerChannel{Pins: []PinFunction{{PA3, AF1_TIM1_2_LPTIM1}, {PB11, AF1_TIM1_2_LPTIM1}}}, - }, - busFreq: APB1_TIM_FREQ, - } - TIM16 = TIM{ - EnableRegister: &stm32.RCC.APB2ENR, - EnableFlag: stm32.RCC_APB2ENR_TIM16EN, - Device: stm32.TIM16, - Channels: [4]TimerChannel{ - TimerChannel{Pins: []PinFunction{{PA6, AF14_TIM2_16_17_LPTIM2}}}, - TimerChannel{Pins: []PinFunction{}}, - TimerChannel{Pins: []PinFunction{}}, - TimerChannel{Pins: []PinFunction{}}, - }, - busFreq: APB2_TIM_FREQ, - } - TIM17 = TIM{ - EnableRegister: &stm32.RCC.APB2ENR, - EnableFlag: stm32.RCC_APB2ENR_TIM17EN, - Device: stm32.TIM17, - Channels: [4]TimerChannel{ - TimerChannel{Pins: []PinFunction{{PA7, AF1_TIM1_2_LPTIM1}, {PB9, AF1_TIM1_2_LPTIM1}}}, - TimerChannel{Pins: []PinFunction{}}, - TimerChannel{Pins: []PinFunction{}}, - TimerChannel{Pins: []PinFunction{}}, - }, - busFreq: APB2_TIM_FREQ, - } -) - -func (t *TIM) registerUPInterrupt() interrupt.Interrupt { - switch t { - case &TIM1: - return interrupt.New(stm32.IRQ_TIM1_UP, TIM1.handleUPInterrupt) - case &TIM2: - return interrupt.New(stm32.IRQ_TIM2, TIM2.handleUPInterrupt) - case &TIM16: - return interrupt.New(stm32.IRQ_TIM16, TIM16.handleUPInterrupt) - case &TIM17: - return interrupt.New(stm32.IRQ_TIM17, TIM17.handleUPInterrupt) - } - - return interrupt.Interrupt{} -} - -func (t *TIM) registerOCInterrupt() interrupt.Interrupt { - switch t { - case &TIM1: - return interrupt.New(stm32.IRQ_TIM1_CC, TIM1.handleOCInterrupt) - case &TIM2: - return interrupt.New(stm32.IRQ_TIM2, TIM2.handleOCInterrupt) - case &TIM16: - return interrupt.New(stm32.IRQ_TIM16, TIM16.handleOCInterrupt) - case &TIM17: - return interrupt.New(stm32.IRQ_TIM17, TIM17.handleOCInterrupt) - } - - return interrupt.Interrupt{} -} - -func (t *TIM) enableMainOutput() { - t.Device.BDTR.SetBits(stm32.TIM_BDTR_MOE) -} - -func initRNG() { - stm32.RCC.AHB3ENR.SetBits(stm32.RCC_AHB3ENR_RNGEN) - - // Enable RNG with config.A (See RM0453 22.6.2) - stm32.RNG.CR.Set(0x40F00D40) // RNG Config. A - stm32.RNG.HTCR.Set(0x17590ABC) // MAGIC NUMBER - stm32.RNG.HTCR.Set(0x0000AA74) // HTCR VALUE - stm32.RNG.CR.Set(0x00F00D4C) // CONFIG A + RNG_EN=1 + IE=1 -} - -//---------- - -type arrtype = uint32 -type arrRegType = volatile.Register32 - -const ( - ARR_MAX = 0x10000 - PSC_MAX = 0x10000 -) - -//---------- Flash related code - -const eraseBlockSizeValue = 2048 - -// eraseBlock of the passed in block number -func eraseBlock(block uint32) error { - waitUntilFlashDone() - - // check if operation is allowed. - if stm32.FLASH.GetSR_PESD() != 0 { - return errFlashCannotErasePage - } - - // clear any previous errors - stm32.FLASH.SR.SetBits(0x3FA) - - // page erase operation - stm32.FLASH.SetCR_PER(1) - defer stm32.FLASH.SetCR_PER(0) - - // set the address to the page to be written - stm32.FLASH.SetCR_PNB(block) - defer stm32.FLASH.SetCR_PNB(0) - - // start the page erase - stm32.FLASH.SetCR_STRT(1) - - waitUntilFlashDone() - - if err := checkError(); err != nil { - return err - } - - return nil -} - -const writeBlockSize = 8 - -func writeFlashData(address uintptr, data []byte) (int, error) { - if len(data)%writeBlockSize != 0 { - return 0, errFlashInvalidWriteLength - } - - waitUntilFlashDone() - - // check if operation is allowed - if stm32.FLASH.GetSR_PESD() != 0 { - return 0, errFlashNotAllowedWriteData - } - - // clear any previous errors - stm32.FLASH.SR.SetBits(0x3FA) - - for j := 0; j < len(data); j += writeBlockSize { - // start page write operation - stm32.FLASH.SetCR_PG(1) - - // write first word using double-word high order word - *(*uint32)(unsafe.Pointer(address)) = binary.LittleEndian.Uint32(data[j : j+writeBlockSize/2]) - - address += writeBlockSize / 2 - - // write second word using double-word low order word - *(*uint32)(unsafe.Pointer(address)) = binary.LittleEndian.Uint32(data[j+writeBlockSize/2 : j+writeBlockSize]) - - waitUntilFlashDone() - - if err := checkError(); err != nil { - return j, err - } - - // end flash write - stm32.FLASH.SetCR_PG(0) - address += writeBlockSize / 2 - } - - return len(data), nil -} - -func waitUntilFlashDone() { - for stm32.FLASH.GetSR_BSY() != 0 { - } - - for stm32.FLASH.GetSR_CFGBSY() != 0 { - } -} - -var ( - errFlashPGS = errors.New("errFlashPGS") - errFlashSIZE = errors.New("errFlashSIZE") - errFlashPGA = errors.New("errFlashPGA") - errFlashWRP = errors.New("errFlashWRP") - errFlashPROG = errors.New("errFlashPROG") -) - -func checkError() error { - switch { - case stm32.FLASH.GetSR_PGSERR() != 0: - return errFlashPGS - case stm32.FLASH.GetSR_SIZERR() != 0: - return errFlashSIZE - case stm32.FLASH.GetSR_PGAERR() != 0: - return errFlashPGA - case stm32.FLASH.GetSR_WRPERR() != 0: - return errFlashWRP - case stm32.FLASH.GetSR_PROGERR() != 0: - return errFlashPROG - } - - return nil -} diff --git a/emb/machine/machine_tkey.go b/emb/machine/machine_tkey.go deleted file mode 100644 index 78863d8..0000000 --- a/emb/machine/machine_tkey.go +++ /dev/null @@ -1,234 +0,0 @@ -//go:build tkey - -package machine - -import ( - "device/tkey" - "errors" - "strconv" -) - -const deviceName = "TKey" - -// GPIO pins modes are only here to match the Pin interface. -// The actual configuration is fixed in the hardware. -const ( - PinOutput PinMode = iota - PinInput - PinInputPullup - PinInputPulldown -) - -const ( - LED_BLUE = Pin(tkey.TK1_MMIO_TK1_LED_B_BIT) - LED_GREEN = Pin(tkey.TK1_MMIO_TK1_LED_G_BIT) - LED_RED = Pin(tkey.TK1_MMIO_TK1_LED_R_BIT) - - LED = LED_GREEN - - TKEY_TOUCH = Pin(3) // 3 is unused, but we need a value here to match the Pin interface. - BUTTON = TKEY_TOUCH - - GPIO1 = Pin(tkey.TK1_MMIO_TK1_GPIO1_BIT + 8) - GPIO2 = Pin(tkey.TK1_MMIO_TK1_GPIO2_BIT + 8) - GPIO3 = Pin(tkey.TK1_MMIO_TK1_GPIO3_BIT + 8) - GPIO4 = Pin(tkey.TK1_MMIO_TK1_GPIO4_BIT + 8) -) - -var touchConfig, gpio1Config, gpio2Config PinConfig - -// No config needed for TKey, just to match the Pin interface. -func (p Pin) Configure(config PinConfig) { - switch p { - case BUTTON: - touchConfig = config - - // Clear any pending touch events. - tkey.TOUCH.STATUS.Set(0) - case GPIO1: - gpio1Config = config - case GPIO2: - gpio2Config = config - } -} - -// Set pin to high or low. -func (p Pin) Set(high bool) { - switch p { - case LED_BLUE, LED_GREEN, LED_RED: - if high { - tkey.TK1.LED.SetBits(1 << uint(p)) - } else { - tkey.TK1.LED.ClearBits(1 << uint(p)) - } - case GPIO3, GPIO4: - if high { - tkey.TK1.GPIO.SetBits(1 << uint(p-8)) - } else { - tkey.TK1.GPIO.ClearBits(1 << uint(p-8)) - } - } -} - -// Get returns the current value of a pin. -func (p Pin) Get() bool { - pushed := false - mode := PinInput - - switch p { - case BUTTON: - mode = touchConfig.Mode - if tkey.TOUCH.STATUS.HasBits(1) { - tkey.TOUCH.STATUS.Set(0) - pushed = true - } - case GPIO1: - mode = gpio1Config.Mode - pushed = tkey.TK1.GPIO.HasBits(1 << uint(p-8)) - case GPIO2: - mode = gpio2Config.Mode - pushed = tkey.TK1.GPIO.HasBits(1 << uint(p-8)) - case GPIO3, GPIO4: - mode = PinOutput - pushed = tkey.TK1.GPIO.HasBits(1 << uint(p-8)) - case LED_BLUE, LED_GREEN, LED_RED: - mode = PinOutput - pushed = tkey.TK1.LED.HasBits(1 << uint(p)) - } - - switch mode { - case PinInputPullup: - return !pushed - case PinInput, PinInputPulldown, PinOutput: - return pushed - } - - return false -} - -type UART struct { - Bus *tkey.UART_Type -} - -var ( - DefaultUART = UART0 - UART0 = &_UART0 - _UART0 = UART{Bus: tkey.UART} -) - -// The TKey UART is fixed at 62500 baud, 8N1. -func (uart *UART) Configure(config UARTConfig) error { - if !(config.BaudRate == 62500 || config.BaudRate == 0) { - return errors.New("uart: only 62500 baud rate is supported") - } - - return nil -} - -// Write a slice of data bytes to the UART. -func (uart *UART) Write(data []byte) (n int, err error) { - for _, c := range data { - if err := uart.WriteByte(c); err != nil { - return n, err - } - } - return len(data), nil -} - -// WriteByte writes a byte of data to the UART. -func (uart *UART) WriteByte(c byte) error { - for uart.Bus.TX_STATUS.Get() == 0 { - } - - uart.Bus.TX_DATA.Set(uint32(c)) - - return nil -} - -// Buffered returns the number of bytes buffered in the UART. -func (uart *UART) Buffered() int { - return int(uart.Bus.RX_BYTES.Get()) -} - -// ReadByte reads a byte of data from the UART. -func (uart *UART) ReadByte() (byte, error) { - for uart.Bus.RX_STATUS.Get() == 0 { - } - - return byte(uart.Bus.RX_DATA.Get()), nil -} - -// DTR is not available on the TKey. -func (uart *UART) DTR() bool { - return false -} - -// RTS is not available on the TKey. -func (uart *UART) RTS() bool { - return false -} - -// GetRNG returns 32 bits of cryptographically secure random data -func GetRNG() (uint32, error) { - for tkey.TRNG.STATUS.Get() == 0 { - } - - return uint32(tkey.TRNG.ENTROPY.Get()), nil -} - -// DesignName returns the FPGA design name. -func DesignName() (string, string) { - n0 := tkey.TK1.NAME0.Get() - name0 := string([]byte{byte(n0 >> 24), byte(n0 >> 16), byte(n0 >> 8), byte(n0)}) - n1 := tkey.TK1.NAME1.Get() - name1 := string([]byte{byte(n1 >> 24), byte(n1 >> 16), byte(n1 >> 8), byte(n1)}) - - return name0, name1 -} - -// DesignVersion returns the FPGA design version. -func DesignVersion() string { - version := tkey.TK1.VERSION.Get() - - return strconv.Itoa(int(version)) -} - -// CDI returns 8 words of Compound Device Identifier (CDI) generated and written by the firmware when the application is loaded. -func CDI() []byte { - cdi := make([]byte, 32) - for i := 0; i < 8; i++ { - c := tkey.TK1.CDI_FIRST[i].Get() - cdi[i*4] = byte(c >> 24) - cdi[i*4+1] = byte(c >> 16) - cdi[i*4+2] = byte(c >> 8) - cdi[i*4+3] = byte(c) - } - return cdi -} - -// UDI returns 2 words of Unique Device Identifier (UDI). Only available in firmware mode. -func UDI() []byte { - udi := make([]byte, 8) - for i := 0; i < 2; i++ { - c := tkey.TK1.UDI_FIRST[i].Get() - udi[i*4] = byte(c >> 24) - udi[i*4+1] = byte(c >> 16) - udi[i*4+2] = byte(c >> 8) - udi[i*4+3] = byte(c) - } - return udi -} - -// UDS returns 8 words of Unique Device Secret. Part of the FPGA design, changed when provisioning a TKey. -// Only available in firmware mode. UDS is only readable once per power cycle. -func UDS() []byte { - uds := make([]byte, 32) - for i := 0; i < 8; i++ { - c := tkey.UDS.DATA[i].Get() - uds[i*4] = byte(c >> 24) - uds[i*4+1] = byte(c >> 16) - uds[i*4+2] = byte(c >> 8) - uds[i*4+3] = byte(c) - } - return uds -} diff --git a/emb/machine/machine_tkey_rom.go b/emb/machine/machine_tkey_rom.go deleted file mode 100644 index bc7162e..0000000 --- a/emb/machine/machine_tkey_rom.go +++ /dev/null @@ -1,59 +0,0 @@ -//go:build tkey - -package machine - -/* - #define TK1_MMIO_TK1_BLAKE2S 0xff000040 - - typedef unsigned char uint8_t; - typedef unsigned long uint32_t; - typedef unsigned long size_t; - - // blake2s state context - typedef struct { - uint8_t b[64]; // input buffer - uint32_t h[8]; // chained state - uint32_t t[2]; // total number of bytes - size_t c; // pointer for b[] - size_t outlen; // digest size - } blake2s_ctx; - - typedef int (*fw_blake2s_p)(void *out, unsigned long outlen, const void *key, - unsigned long keylen, const void *in, - unsigned long inlen, blake2s_ctx *ctx); - - int blake2s(void *out, unsigned long outlen, const void *key, unsigned long keylen, const void *in, unsigned long inlen) - { - fw_blake2s_p const fw_blake2s = - (fw_blake2s_p) * (volatile uint32_t *)TK1_MMIO_TK1_BLAKE2S; - blake2s_ctx ctx; - - return fw_blake2s(out, outlen, key, keylen, in, inlen, &ctx); - } -*/ -import "C" -import ( - "errors" - "unsafe" -) - -var ( - ErrBLAKE2sInvalid = errors.New("invalid params for call to BLAKE2s") - ErrBLAKE2sFailed = errors.New("call to BLAKE2s failed") -) - -func BLAKE2s(output []byte, key []byte, input []byte) error { - if len(output) == 0 || len(input) == 0 { - return ErrBLAKE2sInvalid - } - - op := unsafe.Pointer(&output[0]) - kp := unsafe.Pointer(&key[0]) - ip := unsafe.Pointer(&input[0]) - - if res := C.blake2s(op, C.size_t(len(output)), kp, C.size_t(len(key)), ip, C.size_t(len(input))); res != 0 { - return ErrBLAKE2sFailed - } - - return nil -} diff --git a/emb/machine/pdm.go b/emb/machine/pdm.go deleted file mode 100644 index e57ad0f..0000000 --- a/emb/machine/pdm.go +++ /dev/null @@ -1,7 +0,0 @@ -package machine - -type PDMConfig struct { - Stereo bool - DIN Pin - CLK Pin -} diff --git a/emb/machine/pwm.go b/emb/machine/pwm.go deleted file mode 100644 index 06d61b9..0000000 --- a/emb/machine/pwm.go +++ /dev/null @@ -1,21 +0,0 @@ -package machine - -import "errors" - -var ( - ErrPWMPeriodTooLong = errors.New("pwm: period too long") -) - -// PWMConfig allows setting some configuration while configuring a PWM -// peripheral. A zero PWMConfig is ready to use for simple applications such as -// dimming LEDs. -type PWMConfig struct { - // PWM period in nanosecond. Leaving this zero will pick a reasonable period - // value for use with LEDs. - // If you want to configure a frequency instead of a period, you can use the - // following formula to calculate a period from a frequency: - // - // period = 1e9 / frequency - // - Period uint64 -} diff --git a/emb/machine/runtime.go b/emb/machine/runtime.go deleted file mode 100644 index 928a39c..0000000 --- a/emb/machine/runtime.go +++ /dev/null @@ -1,13 +0,0 @@ -package machine - -import ( - _ "unsafe" -) - -// -// This file provides access to runtime package that would not otherwise -// be permitted due to linker dependencies. -// - -//go:linkname gosched runtime.Gosched -func gosched() diff --git a/emb/machine/serial-none.go b/emb/machine/serial-none.go deleted file mode 100644 index 7b65c32..0000000 --- a/emb/machine/serial-none.go +++ /dev/null @@ -1,10 +0,0 @@ -//go:build baremetal && serial.none - -package machine - -// Serial is a null device: writes to it are ignored. -var Serial = NullSerial{} - -func InitSerial() { - Serial.Configure(UARTConfig{}) -} diff --git a/emb/machine/serial-rtt.go b/emb/machine/serial-rtt.go deleted file mode 100644 index 15f6463..0000000 --- a/emb/machine/serial-rtt.go +++ /dev/null @@ -1,150 +0,0 @@ -//go:build baremetal && serial.rtt - -// Implement Segger RTT support. -// This is mostly useful for targets that only have a debug connection -// available, and no serial output (or input). It is somewhat like semihosting, -// but not unusably slow. -// It was originally specified by Segger, but support is available in OpenOCD -// for at least the DAPLink debuggers so I assume it works on any SWD debugger. - -package machine - -import ( - "runtime/interrupt" - "runtime/volatile" - "unsafe" -) - -// This symbol name is known by the compiler, see monitor.go. -var rttSerialInstance rttSerial - -var Serial = &rttSerialInstance - -func InitSerial() { - Serial.Configure(UARTConfig{}) -} - -const ( - // Some constants, see: - // https://github.com/SEGGERMicro/RTT/blob/master/RTT/SEGGER_RTT.h - - rttMaxNumUpBuffers = 1 - rttMaxNumDownBuffers = 1 - rttBufferSizeUp = 1024 - rttBufferSizeDown = 16 - - rttModeNoBlockSkip = 0 - rttModeNoBlockTrim = 1 - rttModeBlockIfFifoFull = 2 -) - -// The debugger knows about the layout of this struct, so it must not change. -// This is SEGGER_RTT_CB. -type rttControlBlock struct { - id [16]volatile.Register8 - maxNumUpBuffers int32 - maxNumDownBuffers int32 - buffersUp [rttMaxNumUpBuffers]rttBuffer - buffersDown [rttMaxNumDownBuffers]rttBuffer -} - -// Up or down buffer. -// This is SEGGER_RTT_BUFFER_UP and SEGGER_RTT_BUFFER_DOWN. -type rttBuffer struct { - name *byte - buffer *volatile.Register8 - bufferSize uint32 - writeOffset volatile.Register32 - readOffset volatile.Register32 - flags uint32 -} - -// Static buffers, for the default up and down buffer. -var ( - rttBufferUpData [rttBufferSizeUp]volatile.Register8 - rttBufferDownData [rttBufferSizeDown]volatile.Register8 -) - -type rttSerial struct { - rttControlBlock -} - -func (s *rttSerial) Configure(config UARTConfig) error { - s.maxNumUpBuffers = rttMaxNumUpBuffers - s.maxNumDownBuffers = rttMaxNumDownBuffers - - s.buffersUp[0].name = &[]byte("Terminal\x00")[0] - s.buffersUp[0].buffer = &rttBufferUpData[0] - s.buffersUp[0].bufferSize = rttBufferSizeUp - s.buffersUp[0].flags = rttModeNoBlockSkip - - s.buffersDown[0].name = &[]byte("Terminal\x00")[0] - s.buffersDown[0].buffer = &rttBufferDownData[0] - s.buffersDown[0].bufferSize = rttBufferSizeDown - s.buffersDown[0].flags = rttModeNoBlockSkip - - id := "SEGGER RTT" - for i := 0; i < len(id); i++ { - s.id[i].Set(id[i]) - } - - return nil -} - -func (b *rttBuffer) writeByte(c byte) { - state := interrupt.Disable() - readOffset := b.readOffset.Get() - writeOffset := b.writeOffset.Get() - newWriteOffset := writeOffset + 1 - if newWriteOffset == b.bufferSize { - newWriteOffset = 0 - } - if newWriteOffset != readOffset { - unsafe.Slice(b.buffer, b.bufferSize)[writeOffset].Set(c) - b.writeOffset.Set(newWriteOffset) - } - interrupt.Restore(state) -} - -func (b *rttBuffer) readByte() byte { - readOffset := b.readOffset.Get() - writeOffset := b.writeOffset.Get() - for readOffset == writeOffset { - readOffset = b.readOffset.Get() - } - c := unsafe.Slice(b.buffer, b.bufferSize)[readOffset].Get() - b.readOffset.Set(readOffset + 1) - return c -} - -func (b *rttBuffer) buffered() int { - readOffset := b.readOffset.Get() - writeOffset := b.writeOffset.Get() - return int((writeOffset - readOffset) % rttBufferSizeDown) -} - -// Write a single byte to the RTT output buffer. -// -// This method is set to not be inlined, to avoid blowing up binary size as a -// result of inlining writeByte everywhere a println exists. -// -//go:noinline -func (s *rttSerial) WriteByte(b byte) error { - s.buffersUp[0].writeByte(b) - return nil -} - -func (s *rttSerial) ReadByte() (byte, error) { - return s.buffersDown[0].readByte(), errNoByte -} - -func (s *rttSerial) Buffered() int { - return s.buffersDown[0].buffered() -} - -func (s *rttSerial) Write(data []byte) (n int, err error) { - for _, v := range data { - s.WriteByte(v) - } - return len(data), nil -} diff --git a/emb/machine/serial-uart.go b/emb/machine/serial-uart.go deleted file mode 100644 index e938865..0000000 --- a/emb/machine/serial-uart.go +++ /dev/null @@ -1,10 +0,0 @@ -//go:build baremetal && serial.uart - -package machine - -// Serial is implemented via the default (usually the first) UART on the chip. -var Serial = DefaultUART - -func InitSerial() { - Serial.Configure(UARTConfig{}) -} diff --git a/emb/machine/serial-usb.go b/emb/machine/serial-usb.go deleted file mode 100644 index 6587082..0000000 --- a/emb/machine/serial-usb.go +++ /dev/null @@ -1,10 +0,0 @@ -//go:build baremetal && serial.usb - -package machine - -// Serial is implemented via USB (USB-CDC). -var Serial Serialer - -func InitSerial() { - Serial = USBCDC -} diff --git a/emb/machine/serial.go b/emb/machine/serial.go deleted file mode 100644 index 4aacc50..0000000 --- a/emb/machine/serial.go +++ /dev/null @@ -1,48 +0,0 @@ -package machine - -import "errors" - -var errNoByte = errors.New("machine: no byte read") - -// UARTConfig is a struct with which a UART (or similar object) can be -// configured. The baud rate is usually respected, but TX and RX may be ignored -// depending on the chip and the type of object. -type UARTConfig struct { - BaudRate uint32 - TX Pin - RX Pin - RTS Pin - CTS Pin -} - -// NullSerial is a serial version of /dev/null (or null router): it drops -// everything that is written to it. -type NullSerial struct { -} - -// Configure does nothing: the null serial has no configuration. -func (ns NullSerial) Configure(config UARTConfig) error { - return nil -} - -// WriteByte is a no-op: the null serial doesn't write bytes. -func (ns NullSerial) WriteByte(b byte) error { - return nil -} - -// ReadByte always returns an error because there aren't any bytes to read. -func (ns NullSerial) ReadByte() (byte, error) { - return 0, errNoByte -} - -// Buffered returns how many bytes are buffered in the UART. It always returns 0 -// as there are no bytes to read. -func (ns NullSerial) Buffered() int { - return 0 -} - -// Write is a no-op: none of the data is being written and it will not return an -// error. -func (ns NullSerial) Write(p []byte) (n int, err error) { - return len(p), nil -} diff --git a/emb/machine/spi.go b/emb/machine/spi.go deleted file mode 100644 index 9a1033c..0000000 --- a/emb/machine/spi.go +++ /dev/null @@ -1,29 +0,0 @@ -//go:build !baremetal || atmega || esp32 || fe310 || k210 || nrf || (nxp && !mk66f18) || rp2040 || rp2350 || sam || (stm32 && !stm32f7x2 && !stm32l5x2) - -package machine - -import "errors" - -// SPI phase and polarity configs CPOL and CPHA -const ( - Mode0 = 0 - Mode1 = 1 - Mode2 = 2 - Mode3 = 3 -) - -var ( - ErrTxInvalidSliceSize = errors.New("SPI write and read slices must be same size") - errSPIInvalidMachineConfig = errors.New("SPI port was not configured properly by the machine") -) - -// If you are getting a compile error on this line please check to see you've -// correctly implemented the methods on the SPI type. They must match -// the interface method signatures type to type perfectly. -// If not implementing the SPI type please remove your target from the build tags -// at the top of this file. -var _ interface { // 2 - Configure(config SPIConfig) error - Tx(w, r []byte) error - Transfer(w byte) (byte, error) -} = (*SPI)(nil) diff --git a/emb/machine/spi_tx.go b/emb/machine/spi_tx.go deleted file mode 100644 index 97385bb..0000000 --- a/emb/machine/spi_tx.go +++ /dev/null @@ -1,61 +0,0 @@ -//go:build atmega || fe310 || k210 || (nxp && !mk66f18) || (stm32 && !stm32f7x2 && !stm32l5x2) - -// This file implements the SPI Tx function for targets that don't have a custom -// (faster) implementation for it. - -package machine - -// Tx handles read/write operation for SPI interface. Since SPI is a synchronous write/read -// interface, there must always be the same number of bytes written as bytes read. -// The Tx method knows about this, and offers a few different ways of calling it. -// -// This form sends the bytes in tx buffer, putting the resulting bytes read into the rx buffer. -// Note that the tx and rx buffers must be the same size: -// -// spi.Tx(tx, rx) -// -// This form sends the tx buffer, ignoring the result. Useful for sending "commands" that return zeros -// until all the bytes in the command packet have been received: -// -// spi.Tx(tx, nil) -// -// This form sends zeros, putting the result into the rx buffer. Good for reading a "result packet": -// -// spi.Tx(nil, rx) -func (spi *SPI) Tx(w, r []byte) error { - var err error - - switch { - case w == nil: - // read only, so write zero and read a result. - for i := range r { - r[i], err = spi.Transfer(0) - if err != nil { - return err - } - } - case r == nil: - // write only - for _, b := range w { - _, err = spi.Transfer(b) - if err != nil { - return err - } - } - - default: - // write/read - if len(w) != len(r) { - return ErrTxInvalidSliceSize - } - - for i, b := range w { - r[i], err = spi.Transfer(b) - if err != nil { - return err - } - } - } - - return nil -} diff --git a/emb/machine/uart.go b/emb/machine/uart.go deleted file mode 100644 index 3246258..0000000 --- a/emb/machine/uart.go +++ /dev/null @@ -1,106 +0,0 @@ -//go:build atmega || esp || nrf || sam || sifive || stm32 || k210 || nxp || rp2040 || rp2350 - -package machine - -import "errors" - -var errUARTBufferEmpty = errors.New("UART buffer empty") - -// UARTParity is the parity setting to be used for UART communication. -type UARTParity uint8 - -const ( - // ParityNone means to not use any parity checking. This is - // the most common setting. - ParityNone UARTParity = iota - - // ParityEven means to expect that the total number of 1 bits sent - // should be an even number. - ParityEven - - // ParityOdd means to expect that the total number of 1 bits sent - // should be an odd number. - ParityOdd -) - -// To implement the UART interface for a board, you must declare a concrete type as follows: -// -// type UART struct { -// Buffer *RingBuffer -// } -// -// You can also add additional members to this struct depending on your implementation, -// but the *RingBuffer is required. -// When you are declaring your UARTs for your board, make sure that you also declare the -// RingBuffer using the NewRingBuffer() function when you declare your UART: -// -// UART{Buffer: NewRingBuffer()} -// - -// Read from the RX buffer. -func (uart *UART) Read(data []byte) (n int, err error) { - // check if RX buffer is empty - size := uart.Buffered() - if size == 0 { - return 0, nil - } - - // Make sure we do not read more from buffer than the data slice can hold. - if len(data) < size { - size = len(data) - } - - // only read number of bytes used from buffer - for i := 0; i < size; i++ { - v, _ := uart.ReadByte() - data[i] = v - } - - return size, nil -} - -// WriteByte writes a byte of data over the UART's Tx. -// This function blocks until the data is finished being sent. -func (uart *UART) WriteByte(c byte) error { - err := uart.writeByte(c) - if err != nil { - return err - } - uart.flush() // flush() blocks until all data has been transmitted. - return nil -} - -// Write data over the UART's Tx. -// This function blocks until the data is finished being sent. -func (uart *UART) Write(data []byte) (n int, err error) { - for i, v := range data { - err = uart.writeByte(v) - if err != nil { - return i, err - } - } - uart.flush() // flush() blocks until all data has been transmitted. - return len(data), nil -} - -// ReadByte reads a single byte from the RX buffer. -// If there is no data in the buffer, returns an error. -func (uart *UART) ReadByte() (byte, error) { - // check if RX buffer is empty - buf, ok := uart.Buffer.Get() - if !ok { - return 0, errUARTBufferEmpty - } - return buf, nil -} - -// Buffered returns the number of bytes currently stored in the RX buffer. -func (uart *UART) Buffered() int { - return int(uart.Buffer.Used()) -} - -// Receive handles adding data to the UART's data buffer. -// Usually called by the IRQ handler for a machine. -func (uart *UART) Receive(data byte) { - uart.Buffer.Put(data) -} diff --git a/emb/machine/usb.go b/emb/machine/usb.go deleted file mode 100644 index 434ee0f..0000000 --- a/emb/machine/usb.go +++ /dev/null @@ -1,338 +0,0 @@ -//go:build sam || nrf52840 || rp2040 || rp2350 - -package machine - -import ( - "machine/usb" - "machine/usb/descriptor" - - "errors" -) - -type USBDevice struct { - initcomplete bool - InitEndpointComplete bool -} - -var ( - USBDev = &USBDevice{} - USBCDC Serialer -) - -type Serialer interface { - WriteByte(c byte) error - Write(data []byte) (n int, err error) - Configure(config UARTConfig) error - Buffered() int - ReadByte() (byte, error) - DTR() bool - RTS() bool -} - -var usbDescriptor descriptor.Descriptor - -func usbVendorID() uint16 { - if usb.VendorID != 0 { - return usb.VendorID - } - - return usb_VID -} - -func usbProductID() uint16 { - if usb.ProductID != 0 { - return usb.ProductID - } - - return usb_PID -} - -func usbManufacturer() string { - if usb.Manufacturer != "" { - return usb.Manufacturer - } - - return usb_STRING_MANUFACTURER -} - -func usbProduct() string { - if usb.Product != "" { - return usb.Product - } - - return usb_STRING_PRODUCT -} - -func usbSerial() string { - if usb.Serial != "" { - return usb.Serial - } - return "" -} - -// strToUTF16LEDescriptor converts a utf8 string into a string descriptor -// note: the following code only converts ascii characters to UTF16LE. In order -// to do a "proper" conversion, we would need to pull in the 'unicode/utf16' -// package, which at the time this was written added 512 bytes to the compiled -// binary. -func strToUTF16LEDescriptor(in string, out []byte) { - out[0] = byte(len(out)) - out[1] = descriptor.TypeString - for i, rune := range in { - out[(i<<1)+2] = byte(rune) - out[(i<<1)+3] = 0 - } - return -} - -const cdcLineInfoSize = 7 - -var ( - ErrUSBReadTimeout = errors.New("USB read timeout") - ErrUSBBytesRead = errors.New("USB invalid number of bytes read") - ErrUSBBytesWritten = errors.New("USB invalid number of bytes written") -) - -var ( - usbEndpointDescriptors [NumberOfUSBEndpoints]descriptor.Device - - isEndpointHalt = false - isRemoteWakeUpEnabled = false - - usbConfiguration uint8 - usbSetInterface uint8 -) - -//go:align 4 -var udd_ep_control_cache_buffer [256]uint8 - -//go:align 4 -var udd_ep_in_cache_buffer [NumberOfUSBEndpoints][64]uint8 - -//go:align 4 -var udd_ep_out_cache_buffer [NumberOfUSBEndpoints][64]uint8 - -// usb_trans_buffer max size is 255 since that is max size -// for a descriptor (bLength is 1 byte), and the biggest use -// for this buffer is to transmit string descriptors. If -// this buffer is used for new purposes in future the length -// must be revisited. -var usb_trans_buffer [255]uint8 - -var ( - usbTxHandler [NumberOfUSBEndpoints]func() - usbRxHandler [NumberOfUSBEndpoints]func([]byte) bool - usbSetupHandler [usb.NumberOfInterfaces]func(usb.Setup) bool - usbStallHandler [NumberOfUSBEndpoints]func(usb.Setup) bool -) - -// sendDescriptor creates and sends the various USB descriptor types that -// can be requested by the host. -func sendDescriptor(setup usb.Setup) { - switch setup.WValueH { - case descriptor.TypeConfiguration: - sendUSBPacket(0, usbDescriptor.Configuration, setup.WLength) - return - case descriptor.TypeDevice: - usbDescriptor.Configure(usbVendorID(), usbProductID()) - sendUSBPacket(0, usbDescriptor.Device, setup.WLength) - return - - case descriptor.TypeString: - switch setup.WValueL { - case 0: - usb_trans_buffer[0] = 0x04 - usb_trans_buffer[1] = 0x03 - usb_trans_buffer[2] = 0x09 - usb_trans_buffer[3] = 0x04 - sendUSBPacket(0, usb_trans_buffer[:4], setup.WLength) - - case usb.IPRODUCT: - b := usb_trans_buffer[:(len(usbProduct())<<1)+2] - strToUTF16LEDescriptor(usbProduct(), b) - sendUSBPacket(0, b, setup.WLength) - - case usb.IMANUFACTURER: - b := usb_trans_buffer[:(len(usbManufacturer())<<1)+2] - strToUTF16LEDescriptor(usbManufacturer(), b) - sendUSBPacket(0, b, setup.WLength) - - case usb.ISERIAL: - sz := len(usbSerial()) - if sz == 0 { - SendZlp() - } else { - b := usb_trans_buffer[:(sz<<1)+2] - strToUTF16LEDescriptor(usbSerial(), b) - sendUSBPacket(0, b, setup.WLength) - } - } - return - case descriptor.TypeHIDReport: - if h, ok := usbDescriptor.HID[setup.WIndex]; ok { - sendUSBPacket(0, h, setup.WLength) - return - } - case descriptor.TypeDeviceQualifier: - // skip - default: - } - - // do not know how to handle this message, so return zero - SendZlp() - return -} - -func handleStandardSetup(setup usb.Setup) bool { - switch setup.BRequest { - case usb.GET_STATUS: - usb_trans_buffer[0] = 0 - usb_trans_buffer[1] = 0 - - if setup.BmRequestType != 0 { // endpoint - if isEndpointHalt { - usb_trans_buffer[0] = 1 - } - } - - sendUSBPacket(0, usb_trans_buffer[:2], setup.WLength) - return true - - case usb.CLEAR_FEATURE: - if setup.WValueL == 1 { // DEVICEREMOTEWAKEUP - isRemoteWakeUpEnabled = false - } else if setup.WValueL == 0 { // ENDPOINTHALT - if idx := setup.WIndex & 0x7F; idx < NumberOfUSBEndpoints && usbStallHandler[idx] != nil { - // Host has requested to clear an endpoint stall. If the request is addressed to - // an endpoint with a configured StallHandler, forward the message on. - // The 0x7F mask is used to clear the direction bit from the endpoint number - return usbStallHandler[idx](setup) - } - isEndpointHalt = false - } - SendZlp() - return true - - case usb.SET_FEATURE: - if setup.WValueL == 1 { // DEVICEREMOTEWAKEUP - isRemoteWakeUpEnabled = true - } else if setup.WValueL == 0 { // ENDPOINTHALT - if idx := setup.WIndex & 0x7F; idx < NumberOfUSBEndpoints && usbStallHandler[idx] != nil { - // Host has requested to stall an endpoint. If the request is addressed to - // an endpoint with a configured StallHandler, forward the message on. - // The 0x7F mask is used to clear the direction bit from the endpoint number - return usbStallHandler[idx](setup) - } - isEndpointHalt = true - } - SendZlp() - return true - - case usb.SET_ADDRESS: - return handleUSBSetAddress(setup) - - case usb.GET_DESCRIPTOR: - sendDescriptor(setup) - return true - - case usb.SET_DESCRIPTOR: - return false - - case usb.GET_CONFIGURATION: - usb_trans_buffer[0] = usbConfiguration - sendUSBPacket(0, usb_trans_buffer[:1], setup.WLength) - return true - - case usb.SET_CONFIGURATION: - if setup.BmRequestType&usb.REQUEST_RECIPIENT == usb.REQUEST_DEVICE { - for i := 1; i < len(endPoints); i++ { - initEndpoint(uint32(i), endPoints[i]) - } - - usbConfiguration = setup.WValueL - USBDev.InitEndpointComplete = true - - SendZlp() - return true - } else { - return false - } - - case usb.GET_INTERFACE: - usb_trans_buffer[0] = usbSetInterface - sendUSBPacket(0, usb_trans_buffer[:1], setup.WLength) - return true - - case usb.SET_INTERFACE: - usbSetInterface = setup.WValueL - - SendZlp() - return true - - default: - return true - } -} - -func EnableCDC(txHandler func(), rxHandler func([]byte), setupHandler func(usb.Setup) bool) { - if len(usbDescriptor.Device) == 0 { - usbDescriptor = descriptor.CDC - } - // Initialization of endpoints is required even for non-CDC - ConfigureUSBEndpoint(usbDescriptor, - []usb.EndpointConfig{ - { - Index: usb.CDC_ENDPOINT_ACM, - IsIn: true, - Type: usb.ENDPOINT_TYPE_INTERRUPT, - }, - { - Index: usb.CDC_ENDPOINT_OUT, - IsIn: false, - Type: usb.ENDPOINT_TYPE_BULK, - RxHandler: rxHandler, - }, - { - Index: usb.CDC_ENDPOINT_IN, - IsIn: true, - Type: usb.ENDPOINT_TYPE_BULK, - TxHandler: txHandler, - }, - }, - []usb.SetupConfig{ - { - Index: usb.CDC_ACM_INTERFACE, - Handler: setupHandler, - }, - }) -} - -func ConfigureUSBEndpoint(desc descriptor.Descriptor, epSettings []usb.EndpointConfig, setup []usb.SetupConfig) { - usbDescriptor = desc - - for _, ep := range epSettings { - if ep.IsIn { - endPoints[ep.Index] = uint32(ep.Type | usb.EndpointIn) - if ep.TxHandler != nil { - usbTxHandler[ep.Index] = ep.TxHandler - } - } else { - endPoints[ep.Index] = uint32(ep.Type | usb.EndpointOut) - if ep.RxHandler != nil { - usbRxHandler[ep.Index] = func(b []byte) bool { - ep.RxHandler(b) - return true - } - } else if ep.DelayRxHandler != nil { - usbRxHandler[ep.Index] = ep.DelayRxHandler - } - } - if ep.StallHandler != nil { - usbStallHandler[ep.Index] = ep.StallHandler - } - } - - for _, s := range setup { - usbSetupHandler[s.Index] = s.Handler - } -} diff --git a/emb/machine/virt.go b/emb/machine/virt.go deleted file mode 100644 index 2b28ae6..0000000 --- a/emb/machine/virt.go +++ /dev/null @@ -1,189 +0,0 @@ -//go:build tinygo.riscv32 && virt - -// Machine implementation for VirtIO targets. -// At the moment only QEMU RISC-V is supported, but support for ARM for example -// should not be difficult to add with a change to virtioFindDevice. - -package machine - -import ( - "errors" - "runtime/volatile" - "sync" - "unsafe" -) - -const deviceName = "riscv-qemu" - -func (p Pin) Set(high bool) { - // no pins defined -} - -var rngLock sync.Mutex -var rngDevice *virtioDevice1 -var rngBuf volatile.Register32 - -var errNoRNG = errors.New("machine: no entropy source found") -var errNoRNGData = errors.New("machine: entropy source didn't return enough data") - -// GetRNG returns random numbers from a VirtIO entropy source. -// When running in QEMU, it requires adding the RNG device: -// -// -device virtio-rng-device -func GetRNG() (uint32, error) { - rngLock.Lock() - - // Initialize the device on first use. - if rngDevice == nil { - // Search for an available RNG. - rngDevice = virtioFindDevice(virtioDeviceEntropySource) - if rngDevice == nil { - rngLock.Unlock() - return 0, errNoRNG - } - - // Initialize the device. - rngDevice.status.Set(0) // reset device - rngDevice.status.Set(virtioDeviceStatusAcknowledge) - rngDevice.status.Set(virtioDeviceStatusAcknowledge | virtioDeviceStatusDriver) - rngDevice.hostFeaturesSel.Set(0) - rngDevice.status.Set(virtioDeviceStatusAcknowledge | virtioDeviceStatusDriver | virtioDeviceStatusDriverOk) - rngDevice.guestPageSize.Set(4096) - - // Configure queue, according to section 4.2.4 "Legacy interface". - // Note: we're skipping checks for queuePFM and queueNumMax. - rngDevice.queueSel.Set(0) // use queue 0 (the only queue) - rngDevice.queueNum.Set(1) // use a single buffer in the queue - rngDevice.queueAlign.Set(4096) // default alignment appears to be 4096 - rngDevice.queuePFN.Set(uint32(uintptr(unsafe.Pointer(&rngQueue))) / 4096) - - // Configure the only buffer in the queue (but don't increment - // rngQueue.available yet). - rngQueue.buffers[0].address = uint64(uintptr(unsafe.Pointer(&rngBuf))) - rngQueue.buffers[0].length = uint32(unsafe.Sizeof(rngBuf)) - rngQueue.buffers[0].flags = 2 // 2 means write-only buffer - } - - // Increment the available ring buffer. This doesn't actually change the - // buffer index (it's a ring with a single entry), but the number needs to - // be incremented otherwise the device won't recognize a new buffer. - index := rngQueue.available.index - rngQueue.available.index = index + 1 - rngDevice.queueNotify.Set(0) // notify the device of the 'new' (reused) buffer - for rngQueue.used.index.Get() != index+1 { - // Busy wait until the RNG buffer is filled. - // A better way would be to wait for an interrupt, but since this driver - // implementation is mostly used for testing it's good enough for now. - } - - // Check that we indeed got 4 bytes back. - if rngQueue.used.ring[0].length != 4 { - rngLock.Unlock() - return 0, errNoRNGData - } - - // Read the resulting random numbers. - result := rngBuf.Get() - - rngLock.Unlock() - - return result, nil -} - -// Implement a driver for the VirtIO entropy device. -// https://docs.oasis-open.org/virtio/virtio/v1.2/csd01/virtio-v1.2-csd01.html -// http://wiki.osdev.org/Virtio -// http://www.dumais.io/index.php?article=aca38a9a2b065b24dfa1dee728062a12 - -const ( - virtioDeviceStatusAcknowledge = 1 - virtioDeviceStatusDriver = 2 - virtioDeviceStatusDriverOk = 4 - virtioDeviceStatusFeaturesOk = 8 - virtioDeviceStatusFailed = 128 -) - -const ( - virtioDeviceReserved = iota - virtioDeviceNetworkCard - virtioDeviceBlockDevice - virtioDeviceConsole - virtioDeviceEntropySource - // there are more device types -) - -// VirtIO device version 1 -type virtioDevice1 struct { - magic volatile.Register32 // always 0x74726976 - version volatile.Register32 - deviceID volatile.Register32 - vendorID volatile.Register32 - hostFeatures volatile.Register32 - hostFeaturesSel volatile.Register32 - _ [2]uint32 - guestFeatures volatile.Register32 - guestFeaturesSel volatile.Register32 - guestPageSize volatile.Register32 - _ uint32 - queueSel volatile.Register32 - queueNumMax volatile.Register32 - queueNum volatile.Register32 - queueAlign volatile.Register32 - queuePFN volatile.Register32 - _ [3]uint32 - queueNotify volatile.Register32 - _ [3]uint32 - interruptStatus volatile.Register32 - interruptAck volatile.Register32 - _ [2]uint32 - status volatile.Register32 -} - -// VirtIO queue, with a single buffer. -type virtioQueue struct { - buffers [1]struct { - address uint64 - length uint32 - flags uint16 - next uint16 - } // 16 bytes - - available struct { - flags uint16 - index uint16 - ring [1]uint16 - eventIndex uint16 - } // 8 bytes - - _ [4096 - 16*1 - 8*1]byte // padding (to align on a 4096 byte boundary) - - used struct { - flags uint16 - index volatile.Register16 - ring [1]struct { - index uint32 - length uint32 - } - availEvent uint16 - } -} - -func virtioFindDevice(deviceID uint32) *virtioDevice1 { - // On RISC-V, QEMU defines 8 VirtIO devices starting at 0x10001000 and - // repeating every 0x1000 bytes. - // The memory map can be seen in the QEMU source code: - // https://github.com/qemu/qemu/blob/master/hw/riscv/virt.c - for i := 0; i < 8; i++ { - dev := (*virtioDevice1)(unsafe.Pointer(uintptr(0x10001000 + i*0x1000))) - if dev.magic.Get() != 0x74726976 || dev.version.Get() != 1 || dev.deviceID.Get() != deviceID { - continue - } - return dev - } - return nil -} - -// A VirtIO queue needs to be page-aligned. -// -//go:align 4096 -var rngQueue virtioQueue diff --git a/emb/machine/watchdog.go b/emb/machine/watchdog.go deleted file mode 100644 index 7dbf676..0000000 --- a/emb/machine/watchdog.go +++ /dev/null @@ -1,34 +0,0 @@ -//go:build nrf52840 || nrf52833 || rp2040 || rp2350 || atsamd21 || atsamd51 || atsame5x || stm32 - -package machine - -// WatchdogConfig holds configuration for the watchdog timer. -type WatchdogConfig struct { - // The timeout (in milliseconds) before the watchdog fires. - // - // If the requested timeout exceeds `MaxTimeout` it will be rounded - // down. - TimeoutMillis uint32 -} - -// watchdog must be implemented by any platform supporting watchdog functionality -type watchdog interface { - // Configure the watchdog. - // - // This method should not be called after the watchdog is started and on - // some platforms attempting to reconfigure after starting the watchdog - // is explicitly forbidden / will not work. - Configure(config WatchdogConfig) error - - // Starts the watchdog. - Start() error - - // Update the watchdog, indicating that the app is healthy. - Update() -} - -// Ensure required public symbols var exists and meets interface spec -var _ = watchdog(Watchdog) - -// Ensure required public constants exist -const _ = WatchdogMaxTimeout diff --git a/emb/runtime/volatile/bitband_nxpmk66f18.go b/emb/runtime/volatile/bitband_nxpmk66f18.go deleted file mode 100644 index 289596b..0000000 --- a/emb/runtime/volatile/bitband_nxpmk66f18.go +++ /dev/null @@ -1,78 +0,0 @@ -//go:build nxp && mk66f18 - -package volatile - -import "unsafe" - -const registerBase = 0x40000000 -const registerEnd = 0x40100000 -const bitbandBase = 0x42000000 - -//go:inline -func bitbandAddress(reg uintptr, bit uint8) uintptr { - if uintptr(bit) > 32 { - panic("invalid bit position") - } - if reg < registerBase || reg >= registerEnd { - panic("register is out of range") - } - return (reg-registerBase)*32 + uintptr(bit)*4 + bitbandBase -} - -// Special types that causes loads/stores to be volatile (necessary for -// memory-mapped registers). -type BitRegister struct { - Reg uint32 -} - -// Get returns the of the mapped register bit. It is the volatile equivalent of: -// -// *r.Reg -// -//go:inline -func (r *BitRegister) Get() bool { - return LoadUint32(&r.Reg) != 0 -} - -// Set sets the mapped register bit. It is the volatile equivalent of: -// -// *r.Reg = 1 -// -//go:inline -func (r *BitRegister) Set(v bool) { - var i uint32 - if v { - i = 1 - } - StoreUint32(&r.Reg, i) -} - -// Bit maps bit N of register R to the corresponding bitband address. Bit panics -// if R is not an AIPS or GPIO register or if N is out of range (greater than -// the number of bits in a register minus one). -// -//go:inline -func (r *Register8) Bit(bit uint8) *BitRegister { - ptr := bitbandAddress(uintptr(unsafe.Pointer(&r.Reg)), bit) - return (*BitRegister)(unsafe.Pointer(ptr)) -} - -// Bit maps bit N of register R to the corresponding bitband address. Bit panics -// if R is not an AIPS or GPIO register or if N is out of range (greater than -// the number of bits in a register minus one). -// -//go:inline -func (r *Register16) Bit(bit uint8) *BitRegister { - ptr := bitbandAddress(uintptr(unsafe.Pointer(&r.Reg)), bit) - return (*BitRegister)(unsafe.Pointer(ptr)) -} - -// Bit maps bit N of register R to the corresponding bitband address. Bit panics -// if R is not an AIPS or GPIO register or if N is out of range (greater than -// the number of bits in a register minus one). -// -//go:inline -func (r *Register32) Bit(bit uint8) *BitRegister { - ptr := bitbandAddress(uintptr(unsafe.Pointer(&r.Reg)), bit) - return (*BitRegister)(unsafe.Pointer(ptr)) -} diff --git a/emb/runtime/volatile/register.go b/emb/runtime/volatile/register.go deleted file mode 100644 index d89bb6f..0000000 --- a/emb/runtime/volatile/register.go +++ /dev/null @@ -1,254 +0,0 @@ -package volatile - -// This file defines Register{8,16,32,64} types, which are convenience types for -// volatile register accesses. - -// Special types that causes loads/stores to be volatile (necessary for -// memory-mapped registers). -type Register8 struct { - Reg uint8 -} - -// Get returns the value in the register. It is the volatile equivalent of: -// -// *r.Reg -// -//go:inline -func (r *Register8) Get() uint8 { - return LoadUint8(&r.Reg) -} - -// Set updates the register value. It is the volatile equivalent of: -// -// *r.Reg = value -// -//go:inline -func (r *Register8) Set(value uint8) { - StoreUint8(&r.Reg, value) -} - -// SetBits reads the register, sets the given bits, and writes it back. It is -// the volatile equivalent of: -// -// r.Reg |= value -// -//go:inline -func (r *Register8) SetBits(value uint8) { - StoreUint8(&r.Reg, LoadUint8(&r.Reg)|value) -} - -// ClearBits reads the register, clears the given bits, and writes it back. It -// is the volatile equivalent of: -// -// r.Reg &^= value -// -//go:inline -func (r *Register8) ClearBits(value uint8) { - StoreUint8(&r.Reg, LoadUint8(&r.Reg)&^value) -} - -// HasBits reads the register and then checks to see if the passed bits are set. It -// is the volatile equivalent of: -// -// (*r.Reg & value) > 0 -// -//go:inline -func (r *Register8) HasBits(value uint8) bool { - return (r.Get() & value) > 0 -} - -// ReplaceBits is a helper to simplify setting multiple bits high and/or low at -// once. It is the volatile equivalent of: -// -// r.Reg = (r.Reg & ^(mask << pos)) | value << pos -// -//go:inline -func (r *Register8) ReplaceBits(value uint8, mask uint8, pos uint8) { - StoreUint8(&r.Reg, LoadUint8(&r.Reg)&^(mask< 0 -// -//go:inline -func (r *Register16) HasBits(value uint16) bool { - return (r.Get() & value) > 0 -} - -// ReplaceBits is a helper to simplify setting multiple bits high and/or low at -// once. It is the volatile equivalent of: -// -// r.Reg = (r.Reg & ^(mask << pos)) | value << pos -// -//go:inline -func (r *Register16) ReplaceBits(value uint16, mask uint16, pos uint8) { - StoreUint16(&r.Reg, LoadUint16(&r.Reg)&^(mask< 0 -// -//go:inline -func (r *Register32) HasBits(value uint32) bool { - return (r.Get() & value) > 0 -} - -// ReplaceBits is a helper to simplify setting multiple bits high and/or low at -// once. It is the volatile equivalent of: -// -// r.Reg = (r.Reg & ^(mask << pos)) | value << pos -// -//go:inline -func (r *Register32) ReplaceBits(value uint32, mask uint32, pos uint8) { - StoreUint32(&r.Reg, LoadUint32(&r.Reg)&^(mask< 0 -// -//go:inline -func (r *Register64) HasBits(value uint64) bool { - return (r.Get() & value) > 0 -} - -// ReplaceBits is a helper to simplify setting multiple bits high and/or low at -// once. It is the volatile equivalent of: -// -// r.Reg = (r.Reg & ^(mask << pos)) | value << pos -// -//go:inline -func (r *Register64) ReplaceBits(value uint64, mask uint64, pos uint8) { - StoreUint64(&r.Reg, LoadUint64(&r.Reg)&^(mask<