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

     1  //go:build avr && (atmega328p || atmega328pb)
     2  
     3  package machine
     4  
     5  import (
     6  	"device/avr"
     7  	"runtime/interrupt"
     8  	"runtime/volatile"
     9  )
    10  
    11  // PWM is one PWM peripheral, which consists of a counter and two output
    12  // channels (that can be connected to two fixed pins). You can set the frequency
    13  // using SetPeriod, but only for all the channels in this PWM peripheral at
    14  // once.
    15  type PWM struct {
    16  	num uint8
    17  }
    18  
    19  var (
    20  	Timer0 = PWM{0} // 8 bit timer for PD5 and PD6
    21  	Timer1 = PWM{1} // 16 bit timer for PB1 and PB2
    22  	Timer2 = PWM{2} // 8 bit timer for PB3 and PD3
    23  )
    24  
    25  // Configure enables and configures this PWM.
    26  //
    27  // For the two 8 bit timers, there is only a limited number of periods
    28  // available, namely the CPU frequency divided by 256 and again divided by 1, 8,
    29  // 64, 256, or 1024. For a MCU running at 16MHz, this would be a period of 16µs,
    30  // 128µs, 1024µs, 4096µs, or 16384µs.
    31  func (pwm PWM) Configure(config PWMConfig) error {
    32  	switch pwm.num {
    33  	case 0, 2: // 8-bit timers (Timer/counter 0 and Timer/counter 2)
    34  		// Calculate the timer prescaler.
    35  		// While we could configure a flexible top, that would sacrifice one of
    36  		// the PWM output compare registers and thus a PWM channel. I've chosen
    37  		// to instead limit this timer to a fixed number of frequencies.
    38  		var prescaler uint8
    39  		switch config.Period {
    40  		case 0, (uint64(1e9) * 256 * 1) / uint64(CPUFrequency()):
    41  			prescaler = 1
    42  		case (uint64(1e9) * 256 * 8) / uint64(CPUFrequency()):
    43  			prescaler = 2
    44  		case (uint64(1e9) * 256 * 64) / uint64(CPUFrequency()):
    45  			prescaler = 3
    46  		case (uint64(1e9) * 256 * 256) / uint64(CPUFrequency()):
    47  			prescaler = 4
    48  		case (uint64(1e9) * 256 * 1024) / uint64(CPUFrequency()):
    49  			prescaler = 5
    50  		default:
    51  			return ErrPWMPeriodTooLong
    52  		}
    53  
    54  		if pwm.num == 0 {
    55  			avr.TCCR0B.Set(prescaler)
    56  			// Set the PWM mode to fast PWM (mode = 3).
    57  			avr.TCCR0A.Set(avr.TCCR0A_WGM00 | avr.TCCR0A_WGM01)
    58  			// monotonic timer is using the same time as PWM:0
    59  			// we must adust internal settings of monotonic timer when PWM:0 settings changed
    60  			adjustMonotonicTimer()
    61  		} else {
    62  			avr.TCCR2B.Set(prescaler)
    63  			// Set the PWM mode to fast PWM (mode = 3).
    64  			avr.TCCR2A.Set(avr.TCCR2A_WGM20 | avr.TCCR2A_WGM21)
    65  		}
    66  	case 1: // Timer/counter 1
    67  		// The top value is the number of PWM ticks a PWM period takes. It is
    68  		// initially picked assuming an unlimited counter top and no PWM
    69  		// prescaler.
    70  		var top uint64
    71  		if config.Period == 0 {
    72  			// Use a top appropriate for LEDs. Picking a relatively low period
    73  			// here (0xff) for consistency with the other timers.
    74  			top = 0xff
    75  		} else {
    76  			// The formula below calculates the following formula, optimized:
    77  			//     top = period * (CPUFrequency() / 1e9)
    78  			// By dividing the CPU frequency first (an operation that is easily
    79  			// optimized away) the period has less chance of overflowing.
    80  			top = config.Period * (uint64(CPUFrequency()) / 1000000) / 1000
    81  		}
    82  
    83  		avr.TCCR1A.Set(avr.TCCR1A_WGM11)
    84  
    85  		// The ideal PWM period may be larger than would fit in the PWM counter,
    86  		// which is 16 bits (see maxTop). Therefore, try to make the PWM clock
    87  		// speed lower with a prescaler to make the top value fit the maximum
    88  		// top value.
    89  		const maxTop = 0x10000
    90  		switch {
    91  		case top <= maxTop:
    92  			avr.TCCR1B.Set(3<<3 | 1) // no prescaling
    93  		case top/8 <= maxTop:
    94  			avr.TCCR1B.Set(3<<3 | 2) // divide by 8
    95  			top /= 8
    96  		case top/64 <= maxTop:
    97  			avr.TCCR1B.Set(3<<3 | 3) // divide by 64
    98  			top /= 64
    99  		case top/256 <= maxTop:
   100  			avr.TCCR1B.Set(3<<3 | 4) // divide by 256
   101  			top /= 256
   102  		case top/1024 <= maxTop:
   103  			avr.TCCR1B.Set(3<<3 | 5) // divide by 1024
   104  			top /= 1024
   105  		default:
   106  			return ErrPWMPeriodTooLong
   107  		}
   108  
   109  		// A top of 0x10000 is at 100% duty cycle. Subtract one because the
   110  		// counter counts from 0, not 1 (avoiding an off-by-one).
   111  		top -= 1
   112  
   113  		avr.ICR1H.Set(uint8(top >> 8))
   114  		avr.ICR1L.Set(uint8(top))
   115  	}
   116  	return nil
   117  }
   118  
   119  // SetPeriod updates the period of this PWM peripheral.
   120  // To set a particular frequency, use the following formula:
   121  //
   122  //	period = 1e9 / frequency
   123  //
   124  // If you use a period of 0, a period that works well for LEDs will be picked.
   125  //
   126  // SetPeriod will not change the prescaler, but also won't change the current
   127  // value in any of the channels. This means that you may need to update the
   128  // value for the particular channel.
   129  //
   130  // Note that you cannot pick any arbitrary period after the PWM peripheral has
   131  // been configured. If you want to switch between frequencies, pick the lowest
   132  // frequency (longest period) once when calling Configure and adjust the
   133  // frequency here as needed.
   134  func (pwm PWM) SetPeriod(period uint64) error {
   135  	if pwm.num != 1 {
   136  		return ErrPWMPeriodTooLong // TODO better error message
   137  	}
   138  
   139  	// The top value is the number of PWM ticks a PWM period takes. It is
   140  	// initially picked assuming an unlimited counter top and no PWM
   141  	// prescaler.
   142  	var top uint64
   143  	if period == 0 {
   144  		// Use a top appropriate for LEDs. Picking a relatively low period
   145  		// here (0xff) for consistency with the other timers.
   146  		top = 0xff
   147  	} else {
   148  		// The formula below calculates the following formula, optimized:
   149  		//     top = period * (CPUFrequency() / 1e9)
   150  		// By dividing the CPU frequency first (an operation that is easily
   151  		// optimized away) the period has less chance of overflowing.
   152  		top = period * (uint64(CPUFrequency()) / 1000000) / 1000
   153  	}
   154  
   155  	prescaler := avr.TCCR1B.Get() & 0x7
   156  	switch prescaler {
   157  	case 1:
   158  		top /= 1
   159  	case 2:
   160  		top /= 8
   161  	case 3:
   162  		top /= 64
   163  	case 4:
   164  		top /= 256
   165  	case 5:
   166  		top /= 1024
   167  	}
   168  
   169  	// A top of 0x10000 is at 100% duty cycle. Subtract one because the counter
   170  	// counts from 0, not 1 (avoiding an off-by-one).
   171  	top -= 1
   172  
   173  	if top > 0xffff {
   174  		return ErrPWMPeriodTooLong
   175  	}
   176  
   177  	// Warning: this change is not atomic!
   178  	avr.ICR1H.Set(uint8(top >> 8))
   179  	avr.ICR1L.Set(uint8(top))
   180  
   181  	// ... and because of that, set the counter back to zero to avoid most of
   182  	// the effects of this non-atomicity.
   183  	avr.TCNT1H.Set(0)
   184  	avr.TCNT1L.Set(0)
   185  
   186  	return nil
   187  }
   188  
   189  // Top returns the current counter top, for use in duty cycle calculation. It
   190  // will only change with a call to Configure or SetPeriod, otherwise it is
   191  // constant.
   192  //
   193  // The value returned here is hardware dependent. In general, it's best to treat
   194  // it as an opaque value that can be divided by some number and passed to Set
   195  // (see Set documentation for more information).
   196  func (pwm PWM) Top() uint32 {
   197  	if pwm.num == 1 {
   198  		// Timer 1 has a configurable top value.
   199  		low := avr.ICR1L.Get()
   200  		high := avr.ICR1H.Get()
   201  		return uint32(high)<<8 | uint32(low) + 1
   202  	}
   203  	// Other timers go from 0 to 0xff (0x100 or 256 in total).
   204  	return 256
   205  }
   206  
   207  // Counter returns the current counter value of the timer in this PWM
   208  // peripheral. It may be useful for debugging.
   209  func (pwm PWM) Counter() uint32 {
   210  	switch pwm.num {
   211  	case 0:
   212  		return uint32(avr.TCNT0.Get())
   213  	case 1:
   214  		mask := interrupt.Disable()
   215  		low := avr.TCNT1L.Get()
   216  		high := avr.TCNT1H.Get()
   217  		interrupt.Restore(mask)
   218  		return uint32(high)<<8 | uint32(low)
   219  	case 2:
   220  		return uint32(avr.TCNT2.Get())
   221  	}
   222  	// Unknown PWM.
   223  	return 0
   224  }
   225  
   226  // Period returns the used PWM period in nanoseconds. It might deviate slightly
   227  // from the configured period due to rounding.
   228  func (pwm PWM) Period() uint64 {
   229  	var prescaler uint8
   230  	switch pwm.num {
   231  	case 0:
   232  		prescaler = avr.TCCR0B.Get() & 0x7
   233  	case 1:
   234  		prescaler = avr.TCCR1B.Get() & 0x7
   235  	case 2:
   236  		prescaler = avr.TCCR2B.Get() & 0x7
   237  	}
   238  	top := uint64(pwm.Top())
   239  	switch prescaler {
   240  	case 1: // prescaler 1
   241  		return 1 * top * 1000 / uint64(CPUFrequency()/1e6)
   242  	case 2: // prescaler 8
   243  		return 8 * top * 1000 / uint64(CPUFrequency()/1e6)
   244  	case 3: // prescaler 64
   245  		return 64 * top * 1000 / uint64(CPUFrequency()/1e6)
   246  	case 4: // prescaler 256
   247  		return 256 * top * 1000 / uint64(CPUFrequency()/1e6)
   248  	case 5: // prescaler 1024
   249  		return 1024 * top * 1000 / uint64(CPUFrequency()/1e6)
   250  	default: // unknown clock source
   251  		return 0
   252  	}
   253  }
   254  
   255  // Channel returns a PWM channel for the given pin.
   256  func (pwm PWM) Channel(pin Pin) (uint8, error) {
   257  	pin.Configure(PinConfig{Mode: PinOutput})
   258  	pin.Low()
   259  	switch pwm.num {
   260  	case 0:
   261  		switch pin {
   262  		case PD6: // channel A
   263  			avr.TCCR0A.SetBits(avr.TCCR0A_COM0A1)
   264  			return 0, nil
   265  		case PD5: // channel B
   266  			avr.TCCR0A.SetBits(avr.TCCR0A_COM0B1)
   267  			return 1, nil
   268  		}
   269  	case 1:
   270  		switch pin {
   271  		case PB1: // channel A
   272  			avr.TCCR1A.SetBits(avr.TCCR1A_COM1A1)
   273  			return 0, nil
   274  		case PB2: // channel B
   275  			avr.TCCR1A.SetBits(avr.TCCR1A_COM1B1)
   276  			return 1, nil
   277  		}
   278  	case 2:
   279  		switch pin {
   280  		case PB3: // channel A
   281  			avr.TCCR2A.SetBits(avr.TCCR2A_COM2A1)
   282  			return 0, nil
   283  		case PD3: // channel B
   284  			avr.TCCR2A.SetBits(avr.TCCR2A_COM2B1)
   285  			return 1, nil
   286  		}
   287  	}
   288  	return 0, ErrInvalidOutputPin
   289  }
   290  
   291  // SetInverting sets whether to invert the output of this channel.
   292  // Without inverting, a 25% duty cycle would mean the output is high for 25% of
   293  // the time and low for the rest. Inverting flips the output as if a NOT gate
   294  // was placed at the output, meaning that the output would be 25% low and 75%
   295  // high with a duty cycle of 25%.
   296  //
   297  // Note: the invert state may not be applied on the AVR until the next call to
   298  // ch.Set().
   299  func (pwm PWM) SetInverting(channel uint8, inverting bool) {
   300  	switch pwm.num {
   301  	case 0:
   302  		switch channel {
   303  		case 0: // channel A
   304  			if inverting {
   305  				avr.PORTB.SetBits(1 << 6) // PB6 high
   306  				avr.TCCR0A.SetBits(avr.TCCR0A_COM0A0)
   307  			} else {
   308  				avr.PORTB.ClearBits(1 << 6) // PB6 low
   309  				avr.TCCR0A.ClearBits(avr.TCCR0A_COM0A0)
   310  			}
   311  		case 1: // channel B
   312  			if inverting {
   313  				avr.PORTB.SetBits(1 << 5) // PB5 high
   314  				avr.TCCR0A.SetBits(avr.TCCR0A_COM0B0)
   315  			} else {
   316  				avr.PORTB.ClearBits(1 << 5) // PB5 low
   317  				avr.TCCR0A.ClearBits(avr.TCCR0A_COM0B0)
   318  			}
   319  		}
   320  	case 1:
   321  		// Note: the COM1A0/COM1B0 bit is not set with the configuration below.
   322  		// It will be set the following call to Set(), however.
   323  		switch channel {
   324  		case 0: // channel A, PB1
   325  			if inverting {
   326  				avr.PORTB.SetBits(1 << 1) // PB1 high
   327  			} else {
   328  				avr.PORTB.ClearBits(1 << 1) // PB1 low
   329  			}
   330  		case 1: // channel B, PB2
   331  			if inverting {
   332  				avr.PORTB.SetBits(1 << 2) // PB2 high
   333  			} else {
   334  				avr.PORTB.ClearBits(1 << 2) // PB2 low
   335  			}
   336  		}
   337  	case 2:
   338  		switch channel {
   339  		case 0: // channel A
   340  			if inverting {
   341  				avr.PORTB.SetBits(1 << 3) // PB3 high
   342  				avr.TCCR2A.SetBits(avr.TCCR2A_COM2A0)
   343  			} else {
   344  				avr.PORTB.ClearBits(1 << 3) // PB3 low
   345  				avr.TCCR2A.ClearBits(avr.TCCR2A_COM2A0)
   346  			}
   347  		case 1: // channel B
   348  			if inverting {
   349  				avr.PORTD.SetBits(1 << 3) // PD3 high
   350  				avr.TCCR2A.SetBits(avr.TCCR2A_COM2B0)
   351  			} else {
   352  				avr.PORTD.ClearBits(1 << 3) // PD3 low
   353  				avr.TCCR2A.ClearBits(avr.TCCR2A_COM2B0)
   354  			}
   355  		}
   356  	}
   357  }
   358  
   359  // Set updates the channel value. This is used to control the channel duty
   360  // cycle, in other words the fraction of time the channel output is high (or low
   361  // when inverted). For example, to set it to a 25% duty cycle, use:
   362  //
   363  //	pwm.Set(channel, pwm.Top() / 4)
   364  //
   365  // pwm.Set(channel, 0) will set the output to low and pwm.Set(channel,
   366  // pwm.Top()) will set the output to high, assuming the output isn't inverted.
   367  func (pwm PWM) Set(channel uint8, value uint32) {
   368  	switch pwm.num {
   369  	case 0:
   370  		value := uint16(value)
   371  		switch channel {
   372  		case 0: // channel A
   373  			if value == 0 {
   374  				avr.TCCR0A.ClearBits(avr.TCCR0A_COM0A1)
   375  			} else {
   376  				avr.OCR0A.Set(uint8(value - 1))
   377  				avr.TCCR0A.SetBits(avr.TCCR0A_COM0A1)
   378  			}
   379  		case 1: // channel B
   380  			if value == 0 {
   381  				avr.TCCR0A.ClearBits(avr.TCCR0A_COM0B1)
   382  			} else {
   383  				avr.OCR0B.Set(uint8(value) - 1)
   384  				avr.TCCR0A.SetBits(avr.TCCR0A_COM0B1)
   385  			}
   386  		}
   387  		// monotonic timer is using the same time as PWM:0
   388  		// we must adust internal settings of monotonic timer when PWM:0 settings changed
   389  		adjustMonotonicTimer()
   390  	case 1:
   391  		mask := interrupt.Disable()
   392  		switch channel {
   393  		case 0: // channel A, PB1
   394  			if value == 0 {
   395  				avr.TCCR1A.ClearBits(avr.TCCR1A_COM1A1 | avr.TCCR1A_COM1A0)
   396  			} else {
   397  				value := uint16(value) - 1 // yes, this is safe (it relies on underflow)
   398  				avr.OCR1AH.Set(uint8(value >> 8))
   399  				avr.OCR1AL.Set(uint8(value))
   400  				if avr.PORTB.HasBits(1 << 1) { // is PB1 high?
   401  					// Yes, set the inverting bit.
   402  					avr.TCCR1A.SetBits(avr.TCCR1A_COM1A1 | avr.TCCR1A_COM1A0)
   403  				} else {
   404  					// No, output is non-inverting.
   405  					avr.TCCR1A.SetBits(avr.TCCR1A_COM1A1)
   406  				}
   407  			}
   408  		case 1: // channel B, PB2
   409  			if value == 0 {
   410  				avr.TCCR1A.ClearBits(avr.TCCR1A_COM1B1 | avr.TCCR1A_COM1B0)
   411  			} else {
   412  				value := uint16(value) - 1 // yes, this is safe (it relies on underflow)
   413  				avr.OCR1BH.Set(uint8(value >> 8))
   414  				avr.OCR1BL.Set(uint8(value))
   415  				if avr.PORTB.HasBits(1 << 2) { // is PB2 high?
   416  					// Yes, set the inverting bit.
   417  					avr.TCCR1A.SetBits(avr.TCCR1A_COM1B1 | avr.TCCR1A_COM1B0)
   418  				} else {
   419  					// No, output is non-inverting.
   420  					avr.TCCR1A.SetBits(avr.TCCR1A_COM1B1)
   421  				}
   422  			}
   423  		}
   424  		interrupt.Restore(mask)
   425  	case 2:
   426  		value := uint16(value)
   427  		switch channel {
   428  		case 0: // channel A
   429  			if value == 0 {
   430  				avr.TCCR2A.ClearBits(avr.TCCR2A_COM2A1)
   431  			} else {
   432  				avr.OCR2A.Set(uint8(value - 1))
   433  				avr.TCCR2A.SetBits(avr.TCCR2A_COM2A1)
   434  			}
   435  		case 1: // channel B
   436  			if value == 0 {
   437  				avr.TCCR2A.ClearBits(avr.TCCR2A_COM2B1)
   438  			} else {
   439  				avr.OCR2B.Set(uint8(value - 1))
   440  				avr.TCCR2A.SetBits(avr.TCCR2A_COM2B1)
   441  			}
   442  		}
   443  	}
   444  }
   445  
   446  // Pin Change Interrupts
   447  type PinChange uint8
   448  
   449  const (
   450  	PinRising PinChange = 1 << iota
   451  	PinFalling
   452  	PinToggle = PinRising | PinFalling
   453  )
   454  
   455  func (pin Pin) SetInterrupt(pinChange PinChange, callback func(Pin)) (err error) {
   456  
   457  	switch {
   458  	case pin >= PB0 && pin <= PB7:
   459  		// PCMSK0 - PCINT0-7
   460  		pinStates[0] = avr.PINB.Get()
   461  		pinIndex := pin - PB0
   462  		if pinChange&PinRising > 0 {
   463  			pinCallbacks[0][pinIndex][0] = callback
   464  		}
   465  		if pinChange&PinFalling > 0 {
   466  			pinCallbacks[0][pinIndex][1] = callback
   467  		}
   468  		if callback != nil {
   469  			avr.PCMSK0.SetBits(1 << pinIndex)
   470  		} else {
   471  			avr.PCMSK0.ClearBits(1 << pinIndex)
   472  		}
   473  		avr.PCICR.SetBits(avr.PCICR_PCIE0)
   474  		interrupt.New(avr.IRQ_PCINT0, handlePCINT0Interrupts)
   475  	case pin >= PC0 && pin <= PC7:
   476  		// PCMSK1 - PCINT8-14
   477  		pinStates[1] = avr.PINC.Get()
   478  		pinIndex := pin - PC0
   479  		if pinChange&PinRising > 0 {
   480  			pinCallbacks[1][pinIndex][0] = callback
   481  		}
   482  		if pinChange&PinFalling > 0 {
   483  			pinCallbacks[1][pinIndex][1] = callback
   484  		}
   485  		if callback != nil {
   486  			avr.PCMSK1.SetBits(1 << pinIndex)
   487  		} else {
   488  			avr.PCMSK1.ClearBits(1 << pinIndex)
   489  		}
   490  		avr.PCICR.SetBits(avr.PCICR_PCIE1)
   491  		interrupt.New(avr.IRQ_PCINT1, handlePCINT1Interrupts)
   492  	case pin >= PD0 && pin <= PD7:
   493  		// PCMSK2 - PCINT16-23
   494  		pinStates[2] = avr.PIND.Get()
   495  		pinIndex := pin - PD0
   496  		if pinChange&PinRising > 0 {
   497  			pinCallbacks[2][pinIndex][0] = callback
   498  		}
   499  		if pinChange&PinFalling > 0 {
   500  			pinCallbacks[2][pinIndex][1] = callback
   501  		}
   502  		if callback != nil {
   503  			avr.PCMSK2.SetBits(1 << pinIndex)
   504  		} else {
   505  			avr.PCMSK2.ClearBits(1 << pinIndex)
   506  		}
   507  		avr.PCICR.SetBits(avr.PCICR_PCIE2)
   508  		interrupt.New(avr.IRQ_PCINT2, handlePCINT2Interrupts)
   509  	default:
   510  		return ErrInvalidInputPin
   511  	}
   512  
   513  	return nil
   514  }
   515  
   516  var pinCallbacks [3][8][2]func(Pin)
   517  var pinStates [3]uint8
   518  
   519  func handlePCINTInterrupts(intr uint8, port *volatile.Register8) {
   520  	current := port.Get()
   521  	change := pinStates[intr] ^ current
   522  	pinStates[intr] = current
   523  	for i := uint8(0); i < 8; i++ {
   524  		if (change>>i)&0x01 != 0x01 {
   525  			continue
   526  		}
   527  		pin := Pin(intr*8 + i)
   528  		value := pin.Get()
   529  		if value && pinCallbacks[intr][i][0] != nil {
   530  			pinCallbacks[intr][i][0](pin)
   531  		}
   532  		if !value && pinCallbacks[intr][i][1] != nil {
   533  			pinCallbacks[intr][i][1](pin)
   534  		}
   535  	}
   536  }
   537  
   538  func handlePCINT0Interrupts(intr interrupt.Interrupt) {
   539  	handlePCINTInterrupts(0, avr.PINB)
   540  }
   541  
   542  func handlePCINT1Interrupts(intr interrupt.Interrupt) {
   543  	handlePCINTInterrupts(1, avr.PINC)
   544  }
   545  
   546  func handlePCINT2Interrupts(intr interrupt.Interrupt) {
   547  	handlePCINTInterrupts(2, avr.PIND)
   548  }