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 }