avr-rust / ruduino

Reusable components for the Arduino Uno.
Apache License 2.0
695 stars 49 forks source link

contributing other boards #2

Open dsvensson opened 7 years ago

dsvensson commented 7 years ago

I just tried out this framework on the leonardo/promicro/atmega32u4 and had to change some addresses around to get for example serial working, but I guess the rest need some tweaking too. Do you have any nice idea on how to have different boards in the same code base?

dylanmckay commented 7 years ago

I just tried out this framework on the leonardo/promicro/atmega32u4 and had to change some addresses around to get for example serial working

What addresses were these? Did you have to run a custom linking command?

dylanmckay commented 7 years ago

AVR-LLVM itself supports hundreds of different AVR microcontrollers, so the problem is likely that Rust needs to pass extra arguments to the linker.

dsvensson commented 7 years ago

UDR0, UBRR0H, UBRR0L, UCSR0C, UCSR0B, UCSR0A etc

dylanmckay commented 7 years ago

I'm getting my repositories mixed up haha, cc @shepmaster

shepmaster commented 6 years ago

Do you have any nice idea on how to have different boards in the same code base?

Yeah, that's a big question for this library!

My hope was that basically the giant list of registers could be specified for each chip, perhaps in a module. That should work nowadays.

The hard part comes with selecting the appropriate chipset. My first idea would be to have a feature flag that switches them around (and maybe enables certain parts like what serial features are available).

@dsvensson Could you maybe publish your fork somewhere so we could see what kind of diff you had to make? That might help guide what kind of swapability we need to enable.

dsvensson commented 6 years ago

Going sligthly off-topic... I have very little experience in this area, but wouldn't it make sense to try to align this to the route @japaric is taking with embedded-hal etc, or is his arm efforts just too far away? Thinking otherwise it would be nice to get some cross pollination?

shepmaster commented 6 years ago

wouldn't it make sense to try to align this to the route @japaric is taking with embedded-hal etc, or is his arm efforts just too far away? Thinking otherwise it would be nice to get some cross pollination?

I'm always of two minds on this kind of thing. Having two parallel approaches has the potential for independent discovery of useful ideas. It also has the downside of duplicated effort for the common stuff.

For example, back in ye olde days, there was zinc.rs which offered one way of this type of abstraction. I haven't even looked at the ARM HAL stuff, so I don't know if it's the same idea as zinc or if they started from the same place.

However, @japaric is a smart embedded programmer, so I'd appreciate any input from them!

dsvensson commented 6 years ago

Found a git repo with the datasheets in XML format, so here's a generated set of registers (and the script). Up for debate what the names should be... and maybe newer versions of Atmel Studio has updated XML files that could be used instead for better naming.

http://7b014214dde8b39f.paste.se/

shepmaster commented 6 years ago

Thanks. Would you mind running the script for the atmega328p as well? That way I can compare it to the checked-in version. Any idea about 16-bit register pairs or aliases?

Saved script for reference ```python import xml.etree.ElementTree as ET import argparse import math def bits(n): while n: b = n & (~n+1) yield int(round(math.log(b, 2))) n ^= b def gen_bitfields(name, mask): fields = [None] * 8 for bit in bits(mask): fields[7 - bit] = '{}{}'.format(name, bit) return tuple(fields) def get_bitfields(node): fields = [None] * 8 for bitfield in node.findall('bitfield'): name = bitfield.attrib['name'] mask = int(bitfield.attrib['mask'], 16) for i, bit in enumerate(bits(mask)): if bin(mask).count('1') > 1: fields[7 - bit] = '{}{}'.format(name, i) else: fields[7 - bit] = name return tuple(fields) def get_registers(node): for group in node.findall('.//register-group'): for register in group.findall('register'): name = register.attrib['name'] offset = int(register.attrib['offset'], 16) if 'mask' in register.attrib: # If mask defined, there are no named bitfields mask = int(register.attrib['mask'], 16) if mask > 0xff: # Split between high and low registers yield (offset + 1, name + 'H', gen_bitfields(name + 'H', mask & 0xff00)) yield (offset, name + 'L', gen_bitfields(name + 'L', mask & 0xff)) else: yield (offset, name, gen_bitfields(name, mask)) else: yield (offset, name, get_bitfields(register)) if __name__ == '__main__': # Datasheets can be found at https://github.com/avrxml/AS6-Devices-XML parser = argparse.ArgumentParser() parser.add_argument('datasheet', help='Atmel XML Register Datasheet.') args = parser.parse_args() for offset, name, bitfields in get_registers(ET.parse(args.datasheet).getroot()): fields = ''.join('{:11}'.format((f or '-') + ',') for f in bitfields).rstrip(', ') print('register!(0x{:02X}, {:9} [{:87}]);'.format(offset, name + ',', fields)) """ atmega32u4: register!(0xF4, UEINT, [-, UEINT6, UEINT5, UEINT4, UEINT3, UEINT2, UEINT1, UEINT0 ]); register!(0xF3, UEBCHX, [-, -, -, -, -, UEBCHX2, UEBCHX1, UEBCHX0 ]); register!(0xF2, UEBCLX, [UEBCLX7, UEBCLX6, UEBCLX5, UEBCLX4, UEBCLX3, UEBCLX2, UEBCLX1, UEBCLX0 ]); register!(0xF1, UEDATX, [DAT7, DAT6, DAT5, DAT4, DAT3, DAT2, DAT1, DAT0 ]); register!(0xF0, UEIENX, [FLERRE, NAKINE, -, NAKOUTE, RXSTPE, RXOUTE, STALLEDE, TXINE ]); register!(0xEF, UESTA1X, [-, -, -, -, -, CTRLDIR, CURRBK1, CURRBK0 ]); register!(0xEE, UESTA0X, [CFGOK, OVERFI, UNDERFI, -, DTSEQ1, DTSEQ0, NBUSYBK1, NBUSYBK0 ]); register!(0xED, UECFG1X, [-, EPSIZE2, EPSIZE1, EPSIZE0, EPBK1, EPBK0, ALLOC, - ]); register!(0xEC, UECFG0X, [EPTYPE1, EPTYPE0, -, -, -, -, -, EPDIR ]); register!(0xEB, UECONX, [-, -, STALLRQ, STALLRQC, RSTDT, -, -, EPEN ]); register!(0xEA, UERST, [-, EPRST6, EPRST5, EPRST4, EPRST3, EPRST2, EPRST1, EPRST0 ]); register!(0xE9, UENUM, [-, -, -, -, -, UENUM2, UENUM1, UENUM0 ]); register!(0xE8, UEINTX, [FIFOCON, NAKINI, RWAL, NAKOUTI, RXSTPI, RXOUTI, STALLEDI, TXINI ]); register!(0xE6, UDMFN, [-, -, -, FNCERR, -, -, -, - ]); register!(0xE5, UDFNUMH, [-, -, -, -, -, UDFNUMH10, UDFNUMH9, UDFNUMH8 ]); register!(0xE4, UDFNUML, [UDFNUML7, UDFNUML6, UDFNUML5, UDFNUML4, UDFNUML3, UDFNUML2, UDFNUML1, UDFNUML0 ]); register!(0xE3, UDADDR, [ADDEN, UADD6, UADD5, UADD4, UADD3, UADD2, UADD1, UADD0 ]); register!(0xE2, UDIEN, [-, UPRSME, EORSME, WAKEUPE, EORSTE, SOFE, -, SUSPE ]); register!(0xE1, UDINT, [-, UPRSMI, EORSMI, WAKEUPI, EORSTI, SOFI, -, SUSPI ]); register!(0xE0, UDCON, [-, -, -, -, RSTCPU, LSM, RMWKUP, DETACH ]); register!(0xDA, USBINT, [-, -, -, -, -, -, -, VBUSTI ]); register!(0xD9, USBSTA, [-, -, -, -, SPEED, -, -, VBUS ]); register!(0xD8, USBCON, [USBE, -, FRZCLK, OTGPADE, -, -, -, VBUSTE ]); register!(0xD7, UHWCON, [-, -, -, -, -, -, -, UVREGE ]); register!(0xD4, DT4, [DT4L7, DT4L6, DT4L5, DT4L4, DT4L3, DT4L2, DT4L1, DT4L0 ]); register!(0xD2, OCR4D, [OCR4D7, OCR4D6, OCR4D5, OCR4D4, OCR4D3, OCR4D2, OCR4D1, OCR4D0 ]); register!(0xD1, OCR4C, [OCR4C7, OCR4C6, OCR4C5, OCR4C4, OCR4C3, OCR4C2, OCR4C1, OCR4C0 ]); register!(0xD0, OCR4B, [OCR4B7, OCR4B6, OCR4B5, OCR4B4, OCR4B3, OCR4B2, OCR4B1, OCR4B0 ]); register!(0xCF, OCR4A, [OCR4A7, OCR4A6, OCR4A5, OCR4A4, OCR4A3, OCR4A2, OCR4A1, OCR4A0 ]); register!(0xCE, UDR1, [UDR17, UDR16, UDR15, UDR14, UDR13, UDR12, UDR11, UDR10 ]); register!(0xCD, UBRR1H, [-, -, -, -, UBRR1H11, UBRR1H10, UBRR1H9, UBRR1H8 ]); register!(0xCC, UBRR1L, [UBRR1L7, UBRR1L6, UBRR1L5, UBRR1L4, UBRR1L3, UBRR1L2, UBRR1L1, UBRR1L0 ]); register!(0xCA, UCSR1C, [UMSEL11, UMSEL10, UPM11, UPM10, USBS1, UCSZ11, UCSZ10, UCPOL1 ]); register!(0xC9, UCSR1B, [RXCIE1, TXCIE1, UDRIE1, RXEN1, TXEN1, UCSZ12, RXB81, TXB81 ]); register!(0xC8, UCSR1A, [RXC1, TXC1, UDRE1, FE1, DOR1, UPE1, U2X1, MPCM1 ]); register!(0xC7, CLKSTA, [-, -, -, -, -, -, RCON, EXTON ]); register!(0xC6, CLKSEL1, [RCCKSEL3, RCCKSEL2, RCCKSEL1, RCCKSEL0, EXCKSEL3, EXCKSEL2, EXCKSEL1, EXCKSEL0 ]); register!(0xC5, CLKSEL0, [RCSUT1, RCSUT0, EXSUT1, EXSUT0, RCE, EXTE, -, CLKS ]); register!(0xC4, TCCR4E, [TLOCK4, ENHC4, OC4OE5, OC4OE4, OC4OE3, OC4OE2, OC4OE1, OC4OE0 ]); register!(0xC3, TCCR4D, [FPIE4, FPEN4, FPNC4, FPES4, FPAC4, FPF4, WGM41, WGM40 ]); register!(0xC2, TCCR4C, [COM4A1S, COM4A0S, COM4B1S, COM4B0S, COM4D1, COM4D0, FOC4D, PWM4D ]); register!(0xC1, TCCR4B, [PWM4X, PSR4, DTPS41, DTPS40, CS43, CS42, CS41, CS40 ]); register!(0xC0, TCCR4A, [COM4A1, COM4A0, COM4B1, COM4B0, FOC4A, FOC4B, PWM4A, PWM4B ]); register!(0xBF, TC4H, [-, -, -, -, -, TC4H2, TC4H1, TC4H0 ]); register!(0xBE, TCNT4, [TCNT47, TCNT46, TCNT45, TCNT44, TCNT43, TCNT42, TCNT41, TCNT40 ]); register!(0xBD, TWAMR, [TWAM6, TWAM5, TWAM4, TWAM3, TWAM2, TWAM1, TWAM0, - ]); register!(0xBC, TWCR, [TWINT, TWEA, TWSTA, TWSTO, TWWC, TWEN, -, TWIE ]); register!(0xBB, TWDR, [TWDR7, TWDR6, TWDR5, TWDR4, TWDR3, TWDR2, TWDR1, TWDR0 ]); register!(0xBA, TWAR, [TWA6, TWA5, TWA4, TWA3, TWA2, TWA1, TWA0, TWGCE ]); register!(0xB9, TWSR, [TWS4, TWS3, TWS2, TWS1, TWS0, -, TWPS1, TWPS0 ]); register!(0xB8, TWBR, [TWBR7, TWBR6, TWBR5, TWBR4, TWBR3, TWBR2, TWBR1, TWBR0 ]); register!(0x9D, OCR3CH, [OCR3CH15, OCR3CH14, OCR3CH13, OCR3CH12, OCR3CH11, OCR3CH10, OCR3CH9, OCR3CH8 ]); register!(0x9C, OCR3CL, [OCR3CL7, OCR3CL6, OCR3CL5, OCR3CL4, OCR3CL3, OCR3CL2, OCR3CL1, OCR3CL0 ]); register!(0x9B, OCR3BH, [OCR3BH15, OCR3BH14, OCR3BH13, OCR3BH12, OCR3BH11, OCR3BH10, OCR3BH9, OCR3BH8 ]); register!(0x9A, OCR3BL, [OCR3BL7, OCR3BL6, OCR3BL5, OCR3BL4, OCR3BL3, OCR3BL2, OCR3BL1, OCR3BL0 ]); register!(0x99, OCR3AH, [OCR3AH15, OCR3AH14, OCR3AH13, OCR3AH12, OCR3AH11, OCR3AH10, OCR3AH9, OCR3AH8 ]); register!(0x98, OCR3AL, [OCR3AL7, OCR3AL6, OCR3AL5, OCR3AL4, OCR3AL3, OCR3AL2, OCR3AL1, OCR3AL0 ]); register!(0x97, ICR3H, [ICR3H15, ICR3H14, ICR3H13, ICR3H12, ICR3H11, ICR3H10, ICR3H9, ICR3H8 ]); register!(0x96, ICR3L, [ICR3L7, ICR3L6, ICR3L5, ICR3L4, ICR3L3, ICR3L2, ICR3L1, ICR3L0 ]); register!(0x95, TCNT3H, [TCNT3H15, TCNT3H14, TCNT3H13, TCNT3H12, TCNT3H11, TCNT3H10, TCNT3H9, TCNT3H8 ]); register!(0x94, TCNT3L, [TCNT3L7, TCNT3L6, TCNT3L5, TCNT3L4, TCNT3L3, TCNT3L2, TCNT3L1, TCNT3L0 ]); register!(0x92, TCCR3C, [FOC3A, FOC3B, FOC3C, -, -, -, -, - ]); register!(0x91, TCCR3B, [ICNC3, ICES3, -, WGM31, WGM30, CS32, CS31, CS30 ]); register!(0x90, TCCR3A, [COM3A1, COM3A0, COM3B1, COM3B0, COM3C1, COM3C0, WGM31, WGM30 ]); register!(0x8D, OCR1CH, [OCR1CH15, OCR1CH14, OCR1CH13, OCR1CH12, OCR1CH11, OCR1CH10, OCR1CH9, OCR1CH8 ]); register!(0x8C, OCR1CL, [OCR1CL7, OCR1CL6, OCR1CL5, OCR1CL4, OCR1CL3, OCR1CL2, OCR1CL1, OCR1CL0 ]); register!(0x8B, OCR1BH, [OCR1BH15, OCR1BH14, OCR1BH13, OCR1BH12, OCR1BH11, OCR1BH10, OCR1BH9, OCR1BH8 ]); register!(0x8A, OCR1BL, [OCR1BL7, OCR1BL6, OCR1BL5, OCR1BL4, OCR1BL3, OCR1BL2, OCR1BL1, OCR1BL0 ]); register!(0x89, OCR1AH, [OCR1AH15, OCR1AH14, OCR1AH13, OCR1AH12, OCR1AH11, OCR1AH10, OCR1AH9, OCR1AH8 ]); register!(0x88, OCR1AL, [OCR1AL7, OCR1AL6, OCR1AL5, OCR1AL4, OCR1AL3, OCR1AL2, OCR1AL1, OCR1AL0 ]); register!(0x87, ICR1H, [ICR1H15, ICR1H14, ICR1H13, ICR1H12, ICR1H11, ICR1H10, ICR1H9, ICR1H8 ]); register!(0x86, ICR1L, [ICR1L7, ICR1L6, ICR1L5, ICR1L4, ICR1L3, ICR1L2, ICR1L1, ICR1L0 ]); register!(0x85, TCNT1H, [TCNT1H15, TCNT1H14, TCNT1H13, TCNT1H12, TCNT1H11, TCNT1H10, TCNT1H9, TCNT1H8 ]); register!(0x84, TCNT1L, [TCNT1L7, TCNT1L6, TCNT1L5, TCNT1L4, TCNT1L3, TCNT1L2, TCNT1L1, TCNT1L0 ]); register!(0x82, TCCR1C, [FOC1A, FOC1B, FOC1C, -, -, -, -, - ]); register!(0x81, TCCR1B, [ICNC1, ICES1, -, WGM11, WGM10, CS12, CS11, CS10 ]); register!(0x80, TCCR1A, [COM1A1, COM1A0, COM1B1, COM1B0, COM1C1, COM1C0, WGM11, WGM10 ]); register!(0x7F, DIDR1, [-, -, -, -, -, -, AIN1D, AIN0D ]); register!(0x7E, DIDR0, [ADC7D, ADC6D, ADC5D, ADC4D, ADC3D, ADC2D, ADC1D, ADC0D ]); register!(0x7D, DIDR2, [-, -, ADC13D, ADC12D, ADC11D, ADC10D, ADC9D, ADC8D ]); register!(0x7C, ADMUX, [REFS1, REFS0, ADLAR, MUX4, MUX3, MUX2, MUX1, MUX0 ]); register!(0x7B, ADCSRB, [ADHSM, -, MUX5, ADTS3, -, ADTS2, ADTS1, ADTS0 ]); register!(0x7B, ADCSRB, [-, ACME, -, -, -, -, -, - ]); register!(0x7A, ADCSRA, [ADEN, ADSC, ADATE, ADIF, ADIE, ADPS2, ADPS1, ADPS0 ]); register!(0x79, ADCH, [ADCH15, ADCH14, ADCH13, ADCH12, ADCH11, ADCH10, ADCH9, ADCH8 ]); register!(0x78, ADCL, [ADCL7, ADCL6, ADCL5, ADCL4, ADCL3, ADCL2, ADCL1, ADCL0 ]); register!(0x72, TIMSK4, [OCIE4D, OCIE4A, OCIE4B, -, -, TOIE4, -, - ]); register!(0x71, TIMSK3, [-, -, ICIE3, -, OCIE3C, OCIE3B, OCIE3A, TOIE3 ]); register!(0x6F, TIMSK1, [-, -, ICIE1, -, OCIE1C, OCIE1B, OCIE1A, TOIE1 ]); register!(0x6E, TIMSK0, [-, -, -, -, -, OCIE0B, OCIE0A, TOIE0 ]); register!(0x6B, PCMSK0, [PCMSK07, PCMSK06, PCMSK05, PCMSK04, PCMSK03, PCMSK02, PCMSK01, PCMSK00 ]); register!(0x6A, EICRB, [ISC71, ISC70, ISC61, ISC60, ISC51, ISC50, ISC41, ISC40 ]); register!(0x69, EICRA, [ISC31, ISC30, ISC21, ISC20, ISC11, ISC10, ISC01, ISC00 ]); register!(0x68, PCICR, [-, -, -, -, -, -, -, PCIE0 ]); register!(0x67, RCCTRL, [-, -, -, -, -, -, -, RCFREQ ]); register!(0x66, OSCCAL, [OSCCAL7, OSCCAL6, OSCCAL5, OSCCAL4, OSCCAL3, OSCCAL2, OSCCAL1, OSCCAL0 ]); register!(0x65, PRR1, [PRUSB, -, -, -, PRTIM3, -, -, PRUSART1 ]); register!(0x64, PRR0, [PRTWI, PRTIM2, PRTIM0, -, PRTIM1, PRSPI, PRUSART0, PRADC ]); register!(0x61, CLKPR, [CLKPCE, -, -, -, CLKPS3, CLKPS2, CLKPS1, CLKPS0 ]); register!(0x60, WDTCSR, [WDIF, WDIE, WDP3, WDCE, WDE, WDP2, WDP1, WDP0 ]); register!(0x5F, SREG, [I, T, H, S, V, N, Z, C ]); register!(0x5E, SPH, [SPH15, SPH14, SPH13, SPH12, SPH11, SPH10, SPH9, SPH8 ]); register!(0x5D, SPL, [SPL7, SPL6, SPL5, SPL4, SPL3, SPL2, SPL1, SPL0 ]); register!(0x5C, EIND, [-, -, -, -, -, -, -, EIND0 ]); register!(0x57, SPMCSR, [SPMIE, RWWSB, SIGRD, RWWSRE, BLBSET, PGWRT, PGERS, SPMEN ]); register!(0x55, MCUCR, [JTD, -, -, PUD, -, -, IVSEL, IVCE ]); register!(0x55, MCUCR, [JTD, -, -, -, -, -, -, - ]); register!(0x54, MCUSR, [-, -, -, JTRF, WDRF, BORF, EXTRF, PORF ]); register!(0x54, MCUSR, [-, -, -, JTRF, -, -, -, - ]); register!(0x53, SMCR, [-, -, -, -, SM2, SM1, SM0, SE ]); register!(0x52, PLLFRQ, [PINMUX, PLLUSB, PLLTM1, PLLTM0, PDIV3, PDIV2, PDIV1, PDIV0 ]); register!(0x51, OCDR, [OCDR7, OCDR6, OCDR5, OCDR4, OCDR3, OCDR2, OCDR1, OCDR0 ]); register!(0x50, ACSR, [ACD, ACBG, ACO, ACI, ACIE, ACIC, ACIS1, ACIS0 ]); register!(0x4E, SPDR, [SPDR7, SPDR6, SPDR5, SPDR4, SPDR3, SPDR2, SPDR1, SPDR0 ]); register!(0x4D, SPSR, [SPIF, WCOL, -, -, -, -, -, SPI2X ]); register!(0x4C, SPCR, [SPIE, SPE, DORD, MSTR, CPOL, CPHA, SPR1, SPR0 ]); register!(0x4B, GPIOR2, [GPIOR7, GPIOR6, GPIOR5, GPIOR4, GPIOR3, GPIOR2, GPIOR1, GPIOR0 ]); register!(0x4A, GPIOR1, [GPIOR7, GPIOR6, GPIOR5, GPIOR4, GPIOR3, GPIOR2, GPIOR1, GPIOR0 ]); register!(0x49, PLLCSR, [-, -, -, PINDIV, -, -, PLLE, PLOCK ]); register!(0x48, OCR0B, [OCR0B7, OCR0B6, OCR0B5, OCR0B4, OCR0B3, OCR0B2, OCR0B1, OCR0B0 ]); register!(0x47, OCR0A, [OCR0A7, OCR0A6, OCR0A5, OCR0A4, OCR0A3, OCR0A2, OCR0A1, OCR0A0 ]); register!(0x46, TCNT0, [TCNT07, TCNT06, TCNT05, TCNT04, TCNT03, TCNT02, TCNT01, TCNT00 ]); register!(0x45, TCCR0B, [FOC0A, FOC0B, -, -, WGM02, CS02, CS01, CS00 ]); register!(0x44, TCCR0A, [COM0A1, COM0A0, COM0B1, COM0B0, -, -, WGM01, WGM00 ]); register!(0x43, GTCCR, [TSM, -, -, -, -, -, -, PSRSYNC ]); register!(0x42, EEARH, [-, -, -, -, EEARH11, EEARH10, EEARH9, EEARH8 ]); register!(0x41, EEARL, [EEARL7, EEARL6, EEARL5, EEARL4, EEARL3, EEARL2, EEARL1, EEARL0 ]); register!(0x40, EEDR, [EEDR7, EEDR6, EEDR5, EEDR4, EEDR3, EEDR2, EEDR1, EEDR0 ]); register!(0x3F, EECR, [-, -, EEPM1, EEPM0, EERIE, EEMPE, EEPE, EERE ]); register!(0x3E, GPIOR0, [GPIOR07, GPIOR06, GPIOR05, GPIOR04, GPIOR03, GPIOR02, GPIOR01, GPIOR00 ]); register!(0x3D, EIMSK, [INT7, INT6, INT5, INT4, INT3, INT2, INT1, INT0 ]); register!(0x3C, EIFR, [INTF7, INTF6, INTF5, INTF4, INTF3, INTF2, INTF1, INTF0 ]); register!(0x3B, PCIFR, [-, -, -, -, -, -, -, PCIF0 ]); register!(0x39, TIFR4, [OCF4D, OCF4A, OCF4B, -, -, TOV4, -, - ]); register!(0x38, TIFR3, [-, -, ICF3, -, OCF3C, OCF3B, OCF3A, TOV3 ]); register!(0x36, TIFR1, [-, -, ICF1, -, OCF1C, OCF1B, OCF1A, TOV1 ]); register!(0x35, TIFR0, [-, -, -, -, -, OCF0B, OCF0A, TOV0 ]); register!(0x31, PORTF, [PORTF7, PORTF6, PORTF5, PORTF4, -, -, PORTF1, PORTF0 ]); register!(0x30, DDRF, [DDRF7, DDRF6, DDRF5, DDRF4, -, -, DDRF1, DDRF0 ]); register!(0x2F, PINF, [PINF7, PINF6, PINF5, PINF4, -, -, PINF1, PINF0 ]); register!(0x2E, PORTE, [-, PORTE6, -, -, -, PORTE2, -, - ]); register!(0x2D, DDRE, [-, DDRE6, -, -, -, DDRE2, -, - ]); register!(0x2C, PINE, [-, PINE6, -, -, -, PINE2, -, - ]); register!(0x2B, PORTD, [PORTD7, PORTD6, PORTD5, PORTD4, PORTD3, PORTD2, PORTD1, PORTD0 ]); register!(0x2A, DDRD, [DDRD7, DDRD6, DDRD5, DDRD4, DDRD3, DDRD2, DDRD1, DDRD0 ]); register!(0x29, PIND, [PIND7, PIND6, PIND5, PIND4, PIND3, PIND2, PIND1, PIND0 ]); register!(0x28, PORTC, [PORTC7, PORTC6, -, -, -, -, -, - ]); register!(0x27, DDRC, [DDRC7, DDRC6, -, -, -, -, -, - ]); register!(0x26, PINC, [PINC7, PINC6, -, -, -, -, -, - ]); register!(0x25, PORTB, [PORTB7, PORTB6, PORTB5, PORTB4, PORTB3, PORTB2, PORTB1, PORTB0 ]); register!(0x24, DDRB, [DDRB7, DDRB6, DDRB5, DDRB4, DDRB3, DDRB2, DDRB1, DDRB0 ]); register!(0x23, PINB, [PINB7, PINB6, PINB5, PINB4, PINB3, PINB2, PINB1, PINB0 ]); register!(0x02, EXTENDED, [-, -, -, -, HWBE, BODLEVEL2, BODLEVEL1, BODLEVEL0 ]); register!(0x01, HIGH, [OCDEN, JTAGEN, SPIEN, WDTON, EESAVE, BOOTSZ1, BOOTSZ0, BOOTRST ]); register!(0x00, LOW, [CKDIV8, CKOUT, SUT_CKSEL5,SUT_CKSEL4,SUT_CKSEL3,SUT_CKSEL2,SUT_CKSEL1,SUT_CKSEL0]); register!(0x00, LOCKBIT, [-, -, BLB11, BLB10, BLB01, BLB00, LB1, LB0 ]); """ ```
dsvensson commented 6 years ago

Heh, didn't know about collapsable parts in comments before! Here you go:

ATmega328p ```rust // python pyavr.py AS6-Devices-XML/ATmega328P.xml|sort -r register!(0xC6, UDR0, [UDR07, UDR06, UDR05, UDR04, UDR03, UDR02, UDR01, UDR00 ]); register!(0xC5, UBRR0H, [-, -, -, -, UBRR0H11, UBRR0H10, UBRR0H9, UBRR0H8 ]); register!(0xC4, UBRR0L, [UBRR0L7, UBRR0L6, UBRR0L5, UBRR0L4, UBRR0L3, UBRR0L2, UBRR0L1, UBRR0L0 ]); register!(0xC2, UCSR0C, [UMSEL01, UMSEL00, UPM01, UPM00, USBS0, UCSZ01, UCSZ00, UCPOL0 ]); register!(0xC1, UCSR0B, [RXCIE0, TXCIE0, UDRIE0, RXEN0, TXEN0, UCSZ02, RXB80, TXB80 ]); register!(0xC0, UCSR0A, [RXC0, TXC0, UDRE0, FE0, DOR0, UPE0, U2X0, MPCM0 ]); register!(0xBD, TWAMR, [TWAM6, TWAM5, TWAM4, TWAM3, TWAM2, TWAM1, TWAM0, - ]); register!(0xBC, TWCR, [TWINT, TWEA, TWSTA, TWSTO, TWWC, TWEN, -, TWIE ]); register!(0xBB, TWDR, [TWDR7, TWDR6, TWDR5, TWDR4, TWDR3, TWDR2, TWDR1, TWDR0 ]); register!(0xBA, TWAR, [TWA6, TWA5, TWA4, TWA3, TWA2, TWA1, TWA0, TWGCE ]); register!(0xB9, TWSR, [TWS4, TWS3, TWS2, TWS1, TWS0, -, TWPS1, TWPS0 ]); register!(0xB8, TWBR, [TWBR7, TWBR6, TWBR5, TWBR4, TWBR3, TWBR2, TWBR1, TWBR0 ]); register!(0xB6, ASSR, [-, EXCLK, AS2, TCN2UB, OCR2AUB, OCR2BUB, TCR2AUB, TCR2BUB ]); register!(0xB4, OCR2B, [OCR2B7, OCR2B6, OCR2B5, OCR2B4, OCR2B3, OCR2B2, OCR2B1, OCR2B0 ]); register!(0xB3, OCR2A, [OCR2A7, OCR2A6, OCR2A5, OCR2A4, OCR2A3, OCR2A2, OCR2A1, OCR2A0 ]); register!(0xB2, TCNT2, [TCNT27, TCNT26, TCNT25, TCNT24, TCNT23, TCNT22, TCNT21, TCNT20 ]); register!(0xB1, TCCR2B, [FOC2A, FOC2B, -, -, WGM22, CS22, CS21, CS20 ]); register!(0xB0, TCCR2A, [COM2A1, COM2A0, COM2B1, COM2B0, -, -, WGM21, WGM20 ]); register!(0x8B, OCR1BH, [OCR1BH15, OCR1BH14, OCR1BH13, OCR1BH12, OCR1BH11, OCR1BH10, OCR1BH9, OCR1BH8 ]); register!(0x8A, OCR1BL, [OCR1BL7, OCR1BL6, OCR1BL5, OCR1BL4, OCR1BL3, OCR1BL2, OCR1BL1, OCR1BL0 ]); register!(0x89, OCR1AH, [OCR1AH15, OCR1AH14, OCR1AH13, OCR1AH12, OCR1AH11, OCR1AH10, OCR1AH9, OCR1AH8 ]); register!(0x88, OCR1AL, [OCR1AL7, OCR1AL6, OCR1AL5, OCR1AL4, OCR1AL3, OCR1AL2, OCR1AL1, OCR1AL0 ]); register!(0x87, ICR1H, [ICR1H15, ICR1H14, ICR1H13, ICR1H12, ICR1H11, ICR1H10, ICR1H9, ICR1H8 ]); register!(0x86, ICR1L, [ICR1L7, ICR1L6, ICR1L5, ICR1L4, ICR1L3, ICR1L2, ICR1L1, ICR1L0 ]); register!(0x85, TCNT1H, [TCNT1H15, TCNT1H14, TCNT1H13, TCNT1H12, TCNT1H11, TCNT1H10, TCNT1H9, TCNT1H8 ]); register!(0x84, TCNT1L, [TCNT1L7, TCNT1L6, TCNT1L5, TCNT1L4, TCNT1L3, TCNT1L2, TCNT1L1, TCNT1L0 ]); register!(0x82, TCCR1C, [FOC1A, FOC1B, -, -, -, -, -, - ]); register!(0x81, TCCR1B, [ICNC1, ICES1, -, WGM11, WGM10, CS12, CS11, CS10 ]); register!(0x80, TCCR1A, [COM1A1, COM1A0, COM1B1, COM1B0, -, -, WGM11, WGM10 ]); register!(0x7F, DIDR1, [-, -, -, -, -, -, AIN1D, AIN0D ]); register!(0x7E, DIDR0, [-, -, ADC5D, ADC4D, ADC3D, ADC2D, ADC1D, ADC0D ]); register!(0x7C, ADMUX, [REFS1, REFS0, ADLAR, -, MUX3, MUX2, MUX1, MUX0 ]); register!(0x7B, ADCSRB, [-, ACME, -, -, -, ADTS2, ADTS1, ADTS0 ]); register!(0x7A, ADCSRA, [ADEN, ADSC, ADATE, ADIF, ADIE, ADPS2, ADPS1, ADPS0 ]); register!(0x79, ADCH, [ADCH15, ADCH14, ADCH13, ADCH12, ADCH11, ADCH10, ADCH9, ADCH8 ]); register!(0x78, ADCL, [ADCL7, ADCL6, ADCL5, ADCL4, ADCL3, ADCL2, ADCL1, ADCL0 ]); register!(0x70, TIMSK2, [-, -, -, -, -, OCIE2B, OCIE2A, TOIE2 ]); register!(0x6F, TIMSK1, [-, -, ICIE1, -, -, OCIE1B, OCIE1A, TOIE1 ]); register!(0x6E, TIMSK0, [-, -, -, -, -, OCIE0B, OCIE0A, TOIE0 ]); register!(0x6D, PCMSK2, [PCINT7, PCINT6, PCINT5, PCINT4, PCINT3, PCINT2, PCINT1, PCINT0 ]); register!(0x6C, PCMSK1, [-, PCINT6, PCINT5, PCINT4, PCINT3, PCINT2, PCINT1, PCINT0 ]); register!(0x6B, PCMSK0, [PCINT7, PCINT6, PCINT5, PCINT4, PCINT3, PCINT2, PCINT1, PCINT0 ]); register!(0x69, EICRA, [-, -, -, -, ISC11, ISC10, ISC01, ISC00 ]); register!(0x68, PCICR, [-, -, -, -, -, PCIE2, PCIE1, PCIE0 ]); register!(0x66, OSCCAL, [OSCCAL7, OSCCAL6, OSCCAL5, OSCCAL4, OSCCAL3, OSCCAL2, OSCCAL1, OSCCAL0 ]); register!(0x64, PRR, [PRTWI, PRTIM2, PRTIM0, -, PRTIM1, PRSPI, PRUSART0, PRADC ]); register!(0x61, CLKPR, [CLKPCE, -, -, -, CLKPS3, CLKPS2, CLKPS1, CLKPS0 ]); register!(0x60, WDTCSR, [WDIF, WDIE, WDP3, WDCE, WDE, WDP2, WDP1, WDP0 ]); register!(0x5F, SREG, [I, T, H, S, V, N, Z, C ]); register!(0x5E, SPH, [-, -, -, -, SPH11, SPH10, SPH9, SPH8 ]); register!(0x5D, SPL, [SPL7, SPL6, SPL5, SPL4, SPL3, SPL2, SPL1, SPL0 ]); register!(0x57, SPMCSR, [SPMIE, RWWSB, -, RWWSRE, BLBSET, PGWRT, PGERS, SELFPRGEN ]); register!(0x55, MCUCR, [-, BODS, BODSE, PUD, -, -, IVSEL, IVCE ]); register!(0x54, MCUSR, [-, -, -, -, WDRF, BORF, EXTRF, PORF ]); register!(0x53, SMCR, [-, -, -, -, SM2, SM1, SM0, SE ]); register!(0x50, ACSR, [ACD, ACBG, ACO, ACI, ACIE, ACIC, ACIS1, ACIS0 ]); register!(0x4E, SPDR, [SPDR7, SPDR6, SPDR5, SPDR4, SPDR3, SPDR2, SPDR1, SPDR0 ]); register!(0x4D, SPSR, [SPIF, WCOL, -, -, -, -, -, SPI2X ]); register!(0x4C, SPCR, [SPIE, SPE, DORD, MSTR, CPOL, CPHA, SPR1, SPR0 ]); register!(0x4B, GPIOR2, [GPIOR27, GPIOR26, GPIOR25, GPIOR24, GPIOR23, GPIOR22, GPIOR21, GPIOR20 ]); register!(0x4A, GPIOR1, [GPIOR17, GPIOR16, GPIOR15, GPIOR14, GPIOR13, GPIOR12, GPIOR11, GPIOR10 ]); register!(0x48, OCR0B, [OCR0B7, OCR0B6, OCR0B5, OCR0B4, OCR0B3, OCR0B2, OCR0B1, OCR0B0 ]); register!(0x47, OCR0A, [OCR0A7, OCR0A6, OCR0A5, OCR0A4, OCR0A3, OCR0A2, OCR0A1, OCR0A0 ]); register!(0x46, TCNT0, [TCNT07, TCNT06, TCNT05, TCNT04, TCNT03, TCNT02, TCNT01, TCNT00 ]); register!(0x45, TCCR0B, [FOC0A, FOC0B, -, -, WGM02, CS02, CS01, CS00 ]); register!(0x44, TCCR0A, [COM0A1, COM0A0, COM0B1, COM0B0, -, -, WGM01, WGM00 ]); register!(0x43, GTCCR, [TSM, -, -, -, -, -, PSRASY, - ]); register!(0x43, GTCCR, [TSM, -, -, -, -, -, -, PSRSYNC ]); register!(0x43, GTCCR, [TSM, -, -, -, -, -, -, PSRSYNC ]); register!(0x42, EEARH, [-, -, -, -, -, -, EEARH9, EEARH8 ]); register!(0x41, EEARL, [EEARL7, EEARL6, EEARL5, EEARL4, EEARL3, EEARL2, EEARL1, EEARL0 ]); register!(0x40, EEDR, [EEDR7, EEDR6, EEDR5, EEDR4, EEDR3, EEDR2, EEDR1, EEDR0 ]); register!(0x3F, EECR, [-, -, EEPM1, EEPM0, EERIE, EEMPE, EEPE, EERE ]); register!(0x3E, GPIOR0, [GPIOR07, GPIOR06, GPIOR05, GPIOR04, GPIOR03, GPIOR02, GPIOR01, GPIOR00 ]); register!(0x3D, EIMSK, [-, -, -, -, -, -, INT1, INT0 ]); register!(0x3C, EIFR, [-, -, -, -, -, -, INTF1, INTF0 ]); register!(0x3B, PCIFR, [-, -, -, -, -, PCIF2, PCIF1, PCIF0 ]); register!(0x37, TIFR2, [-, -, -, -, -, OCF2B, OCF2A, TOV2 ]); register!(0x36, TIFR1, [-, -, ICF1, -, -, OCF1B, OCF1A, TOV1 ]); register!(0x35, TIFR0, [-, -, -, -, -, OCF0B, OCF0A, TOV0 ]); register!(0x2B, PORTD, [PORTD7, PORTD6, PORTD5, PORTD4, PORTD3, PORTD2, PORTD1, PORTD0 ]); register!(0x2A, DDRD, [DDRD7, DDRD6, DDRD5, DDRD4, DDRD3, DDRD2, DDRD1, DDRD0 ]); register!(0x29, PIND, [PIND7, PIND6, PIND5, PIND4, PIND3, PIND2, PIND1, PIND0 ]); register!(0x28, PORTC, [-, PORTC6, PORTC5, PORTC4, PORTC3, PORTC2, PORTC1, PORTC0 ]); register!(0x27, DDRC, [-, DDRC6, DDRC5, DDRC4, DDRC3, DDRC2, DDRC1, DDRC0 ]); register!(0x26, PINC, [-, PINC6, PINC5, PINC4, PINC3, PINC2, PINC1, PINC0 ]); register!(0x25, PORTB, [PORTB7, PORTB6, PORTB5, PORTB4, PORTB3, PORTB2, PORTB1, PORTB0 ]); register!(0x24, DDRB, [DDRB7, DDRB6, DDRB5, DDRB4, DDRB3, DDRB2, DDRB1, DDRB0 ]); register!(0x23, PINB, [PINB7, PINB6, PINB5, PINB4, PINB3, PINB2, PINB1, PINB0 ]); register!(0x02, EXTENDED, [-, -, -, -, -, BODLEVEL2, BODLEVEL1, BODLEVEL0 ]); register!(0x01, HIGH, [RSTDISBL, DWEN, SPIEN, WDTON, EESAVE, BOOTSZ1, BOOTSZ0, BOOTRST ]); register!(0x00, LOW, [CKDIV8, CKOUT, SUT_CKSEL5,SUT_CKSEL4,SUT_CKSEL3,SUT_CKSEL2,SUT_CKSEL1,SUT_CKSEL0]); register!(0x00, LOCKBIT, [-, -, BLB11, BLB10, BLB01, BLB00, LB1, LB0 ]); ```
dsvensson commented 6 years ago

Any idea about 16-bit register pairs or aliases?

I'm generating them as H/L, with bits from 0...15, here they are:

// atmega32u4
pub const ADC:    *mut u16 = ADCL    as *mut u16;
pub const EEAR:   *mut u16 = EEARL   as *mut u16;
pub const ICR1:   *mut u16 = ICR1L   as *mut u16;
pub const ICR3:   *mut u16 = ICR3L   as *mut u16;
pub const OCR1A:  *mut u16 = OCR1AL  as *mut u16;
pub const OCR1B:  *mut u16 = OCR1BL  as *mut u16;
pub const OCR1C:  *mut u16 = OCR1CL  as *mut u16;
pub const OCR3A:  *mut u16 = OCR3AL  as *mut u16;
pub const OCR3B:  *mut u16 = OCR3BL  as *mut u16;
pub const OCR3C:  *mut u16 = OCR3CL  as *mut u16;
pub const SP:     *mut u16 = SPL     as *mut u16;
pub const TCNT1:  *mut u16 = TCNT1L  as *mut u16;
pub const TCNT3:  *mut u16 = TCNT3L  as *mut u16;
pub const UBRR1:  *mut u16 = UBRR1L  as *mut u16;
pub const UDFNUM: *mut u16 = UDFNUML as *mut u16;

// atmega328p
pub const ADC:    *mut u16 = ADCL    as *mut u16;
pub const EEAR:   *mut u16 = EEARL   as *mut u16;
pub const ICR1:   *mut u16 = ICR1L   as *mut u16;
pub const OCR1A:  *mut u16 = OCR1AL  as *mut u16;
pub const OCR1B:  *mut u16 = OCR1BL  as *mut u16;
pub const SP:     *mut u16 = SPL     as *mut u16;
pub const TCNT1:  *mut u16 = TCNT1L  as *mut u16;
pub const UBRR0:  *mut u16 = UBRR0L  as *mut u16;

And here is the updated script.

Restioson commented 6 years ago

Side note, does this library have support for the Mega? It does have an increased number of pins compared to the Uno and other similar boards, as well as having (2 iirc) more serial ports, which run on certain pins.

shepmaster commented 6 years ago

@dylanmckay any idea if avrd can be of use here? Specifically, I don't see any of the bits available there.

Restioson commented 6 years ago

AVRd does have the pins afaik. It could solve the problem.

shepmaster commented 6 years ago

AVRd does have the pins afaik

It appears it has access to the pins (bitfield), but isn't currently making use of them.

Restioson commented 6 years ago

What do you mean? The README indicates that you can use them like you would using the arduino library: README example

shepmaster commented 6 years ago

What do you mean? The README indicates that you can use them like you would using the arduino library:

Yes, but this library currently also relies on the pins associated

register!(0x25, PORTB,  [PORTB7,  PORTB6,  PORTB5,  PORTB4,  PORTB3,  PORTB2,  PORTB1,  PORTB0 ]);

I don't see PORTB7 in those docs.

dylanmckay commented 6 years ago

Yeah, we definitely have access to the bitfields from the pack files.

At the moment, the library only uses them in generated documentation.

We can definitely use them to generate PORT[A-Z][0-9] constants.

dylanmckay commented 6 years ago

Can confirm that AVRd has definitions for every register across every device.

shepmaster commented 6 years ago

Just because it was in my head, I wonder what kinds of type safety and structuring we could employ. For example:

struct PORTB;

impl PORTB {
    const PORTB7: u8 = 1 << 0;
}

struct Register(*const u8);

impl From<PORTB> for Register {
    fn from(_: PORTB) -> Self { Register(0x20 as _) }
}

This would make each register its own type, and then we could choose to implement traits across them.

I did something similar locally:

pub trait Information {
    const DDR: *mut u8;
    const IO: *mut u8;
    const PIN: *mut u8;
}

pub struct B;

impl Information for B {
    const DDR: *mut u8 = ::DDRB;
    const IO: *mut u8 = ::PORTB;
    const PIN: *mut u8 = ::PINB;
}
dylanmckay commented 6 years ago

I was thinking if we want the avrd library to do something like this.

I'd really like the library to be quite low level that other devices built atop of, but if we create a trait like this then we can auto generate it for all devices, rather than having to rebuild all of it for the Arduino library.

Another option might be to extract most of avrd to a library. With that, we could add it as a build dependency for Arduino and then use it to generate structures ourselves.

shepmaster commented 6 years ago

Another option might be to extract most of avrd to a library.

That seems like it might be the appropriate path. A rough idea would be that the arduino library would have only generic things like

pub trait Information {
    const DDR: *mut u8;
    const IO: *mut u8;
    const PIN: *mut u8;
}

The user uses avrd (or something built on top of it) in their own build script (insert hand-waving here), generating code like

pub struct B;

impl Information for B {
    const DDR: *mut u8 = ::DDRB;
    const IO: *mut u8 = ::PORTB;
    const PIN: *mut u8 = ::PINB;
}

Which accounts for their specific board (e.g. which PORTx are available). They can then use the combination of the two libraries, effectively dependency-injecting the concrete board information.

This could also allow for the user to choose a serial implementation for macros like println! to use.

A big question in my mind is exactly how abstract we can be. Aren't there some boards that have like... "half" of a PORT defined? Will things like that cause massive pain?

dylanmckay commented 6 years ago

We could abstract it on the GPIO level rather than the port level.

The pack files do say the number of pins supported on each port.

Something like

trait Pin {
    const DDR: *mut u8;
    const PORT: *mut u8;
    const PIN: *mut u8;
    const MASK: u8;
}

struct PB5;

impl Pin for PB5 {
    const DDR: *mut u8 = ::DDRB;
    const PORT: *mut u8 = ::PORTB;
    const PIN: *mut u8 = ::PINB;
    const MASK: u8 = 1<<5;
}
dylanmckay commented 6 years ago

I remember there also being some sort of special IO register that 1 can be written to which will toggle the pin, regardless of its current state.

Because the XOR is done in hardware, it's faster than using PORTB to toggle.

If we abstract this on the pin level, we can write a toggle method to do this optimisation transparently.

shepmaster commented 6 years ago

I remember there also being some sort of special IO register that 1 can be written to which will toggle the pin, regardless of its current state.

Yep, that was one of the things that tripped me up earlier this year, and why I asked you about coalescing 8 consecutive sbi instructions for the same register.

You can see my current set of changes in the ports branch. TL;DR yeah, there's a toggle function.

dylanmckay commented 6 years ago

I've got my own local branch as well, exposing a Pin trait that gets implementations generated per mcu.

I'm also creating a HardwareSerial trait, and if I can understand enough about timers, will hopefully do that too.

dylanmckay commented 6 years ago

Here's my WIP PR avr-rust/arduino#4

Restioson commented 6 years ago

Related: could this be done for serial ports?

Example gist: https://gist.github.com/Restioson/47976cc261a1a9b788114283e98f2308 (Apologies for any mistakes)

dylanmckay commented 6 years ago

Yeah, I've done it for SPI so far.

Restioson commented 6 years ago

Great :smile: