github.com/aykevl/tinygo@v0.5.0/src/machine/machine_atmega.go (about)

     1  // +build avr,atmega
     2  
     3  package machine
     4  
     5  import (
     6  	"device/avr"
     7  )
     8  
     9  // Configure sets the pin to input or output.
    10  func (p GPIO) Configure(config GPIOConfig) {
    11  	if config.Mode == GPIO_OUTPUT { // set output bit
    12  		if p.Pin < 8 {
    13  			*avr.DDRD |= 1 << p.Pin
    14  		} else {
    15  			*avr.DDRB |= 1 << (p.Pin - 8)
    16  		}
    17  	} else { // configure input: clear output bit
    18  		if p.Pin < 8 {
    19  			*avr.DDRD &^= 1 << p.Pin
    20  		} else {
    21  			*avr.DDRB &^= 1 << (p.Pin - 8)
    22  		}
    23  	}
    24  }
    25  
    26  // Get returns the current value of a GPIO pin.
    27  func (p GPIO) Get() bool {
    28  	if p.Pin < 8 {
    29  		val := *avr.PIND & (1 << p.Pin)
    30  		return (val > 0)
    31  	} else {
    32  		val := *avr.PINB & (1 << (p.Pin - 8))
    33  		return (val > 0)
    34  	}
    35  }
    36  
    37  func (p GPIO) getPortMask() (*avr.RegValue, uint8) {
    38  	if p.Pin < 8 {
    39  		return avr.PORTD, 1 << p.Pin
    40  	} else {
    41  		return avr.PORTB, 1 << (p.Pin - 8)
    42  	}
    43  }
    44  
    45  // InitPWM initializes the registers needed for PWM.
    46  func InitPWM() {
    47  	// use waveform generation
    48  	*avr.TCCR0A |= avr.TCCR0A_WGM00
    49  
    50  	// set timer 0 prescale factor to 64
    51  	*avr.TCCR0B |= avr.TCCR0B_CS01 | avr.TCCR0B_CS00
    52  
    53  	// set timer 1 prescale factor to 64
    54  	*avr.TCCR1B |= avr.TCCR1B_CS11
    55  
    56  	// put timer 1 in 8-bit phase correct pwm mode
    57  	*avr.TCCR1A |= avr.TCCR1A_WGM10
    58  
    59  	// set timer 2 prescale factor to 64
    60  	*avr.TCCR2B |= avr.TCCR2B_CS22
    61  
    62  	// configure timer 2 for phase correct pwm (8-bit)
    63  	*avr.TCCR2A |= avr.TCCR2A_WGM20
    64  }
    65  
    66  // Configure configures a PWM pin for output.
    67  func (pwm PWM) Configure() {
    68  	if pwm.Pin < 8 {
    69  		*avr.DDRD |= 1 << pwm.Pin
    70  	} else {
    71  		*avr.DDRB |= 1 << (pwm.Pin - 8)
    72  	}
    73  }
    74  
    75  // Set turns on the duty cycle for a PWM pin using the provided value. On the AVR this is normally a
    76  // 8-bit value ranging from 0 to 255.
    77  func (pwm PWM) Set(value uint16) {
    78  	value8 := value >> 8
    79  	switch pwm.Pin {
    80  	case 3:
    81  		// connect pwm to pin on timer 2, channel B
    82  		*avr.TCCR2A |= avr.TCCR2A_COM2B1
    83  		*avr.OCR2B = avr.RegValue(value8) // set pwm duty
    84  	case 5:
    85  		// connect pwm to pin on timer 0, channel B
    86  		*avr.TCCR0A |= avr.TCCR0A_COM0B1
    87  		*avr.OCR0B = avr.RegValue(value8) // set pwm duty
    88  	case 6:
    89  		// connect pwm to pin on timer 0, channel A
    90  		*avr.TCCR0A |= avr.TCCR0A_COM0A1
    91  		*avr.OCR0A = avr.RegValue(value8) // set pwm duty
    92  	case 9:
    93  		// connect pwm to pin on timer 1, channel A
    94  		*avr.TCCR1A |= avr.TCCR1A_COM1A1
    95  		// this is a 16-bit value, but we only currently allow the low order bits to be set
    96  		*avr.OCR1AL = avr.RegValue(value8) // set pwm duty
    97  	case 10:
    98  		// connect pwm to pin on timer 1, channel B
    99  		*avr.TCCR1A |= avr.TCCR1A_COM1B1
   100  		// this is a 16-bit value, but we only currently allow the low order bits to be set
   101  		*avr.OCR1BL = avr.RegValue(value8) // set pwm duty
   102  	case 11:
   103  		// connect pwm to pin on timer 2, channel A
   104  		*avr.TCCR2A |= avr.TCCR2A_COM2A1
   105  		*avr.OCR2A = avr.RegValue(value8) // set pwm duty
   106  	default:
   107  		panic("Invalid PWM pin")
   108  	}
   109  }
   110  
   111  // I2CConfig is used to store config info for I2C.
   112  type I2CConfig struct {
   113  	Frequency uint32
   114  }
   115  
   116  // Configure is intended to setup the I2C interface.
   117  func (i2c I2C) Configure(config I2CConfig) {
   118  	// Default I2C bus speed is 100 kHz.
   119  	if config.Frequency == 0 {
   120  		config.Frequency = TWI_FREQ_100KHZ
   121  	}
   122  
   123  	// Activate internal pullups for twi.
   124  	*avr.PORTC |= (avr.DIDR0_ADC4D | avr.DIDR0_ADC5D)
   125  
   126  	// Initialize twi prescaler and bit rate.
   127  	*avr.TWSR |= (avr.TWSR_TWPS0 | avr.TWSR_TWPS1)
   128  
   129  	// twi bit rate formula from atmega128 manual pg. 204:
   130  	// SCL Frequency = CPU Clock Frequency / (16 + (2 * TWBR))
   131  	// NOTE: TWBR should be 10 or higher for master mode.
   132  	// It is 72 for a 16mhz board with 100kHz TWI
   133  	*avr.TWBR = avr.RegValue(((CPU_FREQUENCY / config.Frequency) - 16) / 2)
   134  
   135  	// Enable twi module.
   136  	*avr.TWCR = avr.TWCR_TWEN
   137  }
   138  
   139  // Tx does a single I2C transaction at the specified address.
   140  // It clocks out the given address, writes the bytes in w, reads back len(r)
   141  // bytes and stores them in r, and generates a stop condition on the bus.
   142  func (i2c I2C) Tx(addr uint16, w, r []byte) error {
   143  	if len(w) != 0 {
   144  		i2c.start(uint8(addr), true) // start transmission for writing
   145  		for _, b := range w {
   146  			i2c.writeByte(b)
   147  		}
   148  	}
   149  	if len(r) != 0 {
   150  		i2c.start(uint8(addr), false) // re-start transmission for reading
   151  		for i := range r {            // read each char
   152  			r[i] = i2c.readByte()
   153  		}
   154  	}
   155  	if len(w) != 0 || len(r) != 0 {
   156  		// Stop the transmission after it has been started.
   157  		i2c.stop()
   158  	}
   159  	return nil
   160  }
   161  
   162  // start starts an I2C communication session.
   163  func (i2c I2C) start(address uint8, write bool) {
   164  	// Clear TWI interrupt flag, put start condition on SDA, and enable TWI.
   165  	*avr.TWCR = (avr.TWCR_TWINT | avr.TWCR_TWSTA | avr.TWCR_TWEN)
   166  
   167  	// Wait till start condition is transmitted.
   168  	for (*avr.TWCR & avr.TWCR_TWINT) == 0 {
   169  	}
   170  
   171  	// Write 7-bit shifted peripheral address.
   172  	address <<= 1
   173  	if !write {
   174  		address |= 1 // set read flag
   175  	}
   176  	i2c.writeByte(address)
   177  }
   178  
   179  // stop ends an I2C communication session.
   180  func (i2c I2C) stop() {
   181  	// Send stop condition.
   182  	*avr.TWCR = (avr.TWCR_TWEN | avr.TWCR_TWINT | avr.TWCR_TWSTO)
   183  
   184  	// Wait for stop condition to be executed on bus.
   185  	for (*avr.TWCR & avr.TWCR_TWSTO) == 0 {
   186  	}
   187  }
   188  
   189  // writeByte writes a single byte to the I2C bus.
   190  func (i2c I2C) writeByte(data byte) {
   191  	// Write data to register.
   192  	*avr.TWDR = avr.RegValue(data)
   193  
   194  	// Clear TWI interrupt flag and enable TWI.
   195  	*avr.TWCR = (avr.TWCR_TWEN | avr.TWCR_TWINT)
   196  
   197  	// Wait till data is transmitted.
   198  	for (*avr.TWCR & avr.TWCR_TWINT) == 0 {
   199  	}
   200  }
   201  
   202  // readByte reads a single byte from the I2C bus.
   203  func (i2c I2C) readByte() byte {
   204  	// Clear TWI interrupt flag and enable TWI.
   205  	*avr.TWCR = (avr.TWCR_TWEN | avr.TWCR_TWINT | avr.TWCR_TWEA)
   206  
   207  	// Wait till read request is transmitted.
   208  	for (*avr.TWCR & avr.TWCR_TWINT) == 0 {
   209  	}
   210  
   211  	return byte(*avr.TWDR)
   212  }
   213  
   214  // UART on the AVR.
   215  type UART struct {
   216  	Buffer *RingBuffer
   217  }
   218  
   219  // Configure the UART on the AVR. Defaults to 9600 baud on Arduino.
   220  func (uart UART) Configure(config UARTConfig) {
   221  	if config.BaudRate == 0 {
   222  		config.BaudRate = 9600
   223  	}
   224  
   225  	// Set baud rate based on prescale formula from
   226  	// https://www.microchip.com/webdoc/AVRLibcReferenceManual/FAQ_1faq_wrong_baud_rate.html
   227  	// ((F_CPU + UART_BAUD_RATE * 8L) / (UART_BAUD_RATE * 16L) - 1)
   228  	ps := ((CPU_FREQUENCY+config.BaudRate*8)/(config.BaudRate*16) - 1)
   229  	*avr.UBRR0H = avr.RegValue(ps >> 8)
   230  	*avr.UBRR0L = avr.RegValue(ps & 0xff)
   231  
   232  	// enable RX, TX and RX interrupt
   233  	*avr.UCSR0B = avr.UCSR0B_RXEN0 | avr.UCSR0B_TXEN0 | avr.UCSR0B_RXCIE0
   234  
   235  	// 8-bits data
   236  	*avr.UCSR0C = avr.UCSR0C_UCSZ01 | avr.UCSR0C_UCSZ00
   237  }
   238  
   239  // WriteByte writes a byte of data to the UART.
   240  func (uart UART) WriteByte(c byte) error {
   241  	// Wait until UART buffer is not busy.
   242  	for (*avr.UCSR0A & avr.UCSR0A_UDRE0) == 0 {
   243  	}
   244  	*avr.UDR0 = avr.RegValue(c) // send char
   245  	return nil
   246  }
   247  
   248  //go:interrupt USART_RX_vect
   249  func handleUSART_RX() {
   250  	// Read register to clear it.
   251  	data := *avr.UDR0
   252  
   253  	// Ensure no error.
   254  	if (*avr.UCSR0A & (avr.UCSR0A_FE0 | avr.UCSR0A_DOR0 | avr.UCSR0A_UPE0)) == 0 {
   255  		// Put data from UDR register into buffer.
   256  		UART0.Receive(byte(data))
   257  	}
   258  }