github.com/tinygo-org/tinygo@v0.31.3-0.20240404173401-90b0bf646c27/src/machine/machine_atmega.go (about)

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