avr-rust / ruduino

Reusable components for the Arduino Uno.
Apache License 2.0
704 stars 50 forks source link

ATmega32U4 support: collect register definitions from multiple modules #48

Open gergoerdi opened 1 year ago

gergoerdi commented 1 year ago

I'd like to use Rust to develop for the ArduBoy, which uses an ATmega32U4, which I believe is the same mcu as used on the Arduino Leonardo. So there should be quite a lot of boards out there using it.

Ruduino's core_generator chokes on the 16u4 and the 32u4 as-is because they have PDI and PDO pins in their SPI definition. I think these can be safely ignored as they are only used for in-circuit programming.

However, if we get over this hump, we get a more severe problem: registers that are defined "piecewise" at multiple locations in the packfile. For example, on the 32u4 ADCSRB is defined in two modules, in AC and in ADC. With core_generator's naive handling of registers, these end up as duplicate definitions in atmega32u4.rs:

#[allow(non_camel_case_types)]
pub struct ADCSRB;

impl ADCSRB {
    pub const ACME: RegisterBits<Self> = RegisterBits::new(0x40);
    pub const ACME0: RegisterBits<Self> = RegisterBits::new(1<<6);

}

impl Register for ADCSRB {
    type T = u8;
    const ADDRESS: *mut u8 = 0x7b as *mut u8;
}
#[allow(non_camel_case_types)]
pub struct ADCSRB;

impl ADCSRB {
    pub const ADHSM: RegisterBits<Self> = RegisterBits::new(0x80);
    pub const ADHSM0: RegisterBits<Self> = RegisterBits::new(1<<7);

    pub const MUX5: RegisterBits<Self> = RegisterBits::new(0x20);
    pub const MUX50: RegisterBits<Self> = RegisterBits::new(1<<5);

    pub const ADTS: RegisterBits<Self> = RegisterBits::new(0x17);
    pub const ADTS0: RegisterBits<Self> = RegisterBits::new(1<<0);
    pub const ADTS1: RegisterBits<Self> = RegisterBits::new(1<<1);
    pub const ADTS2: RegisterBits<Self> = RegisterBits::new(1<<2);
    pub const ADTS3: RegisterBits<Self> = RegisterBits::new(1<<4);

}

impl Register for ADCSRB {
    type T = u8;
    const ADDRESS: *mut u8 = 0x7b as *mut u8;
}
gergoerdi commented 1 year ago

The next problem is the 16-bit timer module TC16, for which the following code is generated:

impl modules::Timer16 for Timer16 {
    type CompareA = OCR3A;
    type CompareB = OCR3B;
    type Counter = TCNT3;
    type ControlA = TCCR3A;
    type ControlB = TCCR3B;
    type ControlC = TCCR3C;
    type InterruptMask = TIMSK3;
    type InterruptFlag = TIFR3;
    const CS0: RegisterBits<Self::ControlB> = Self::ControlB::CS10;
    const CS1: RegisterBits<Self::ControlB> = Self::ControlB::CS11;
    const CS2: RegisterBits<Self::ControlB> = Self::ControlB::CS12;
    const WGM0: RegisterBits<Self::ControlA> = Self::ControlA::WGM10;
    const WGM1: RegisterBits<Self::ControlA> = Self::ControlA::WGM11;
    const WGM2: RegisterBits<Self::ControlB> = Self::ControlB::WGM10;
    const WGM3: RegisterBits<Self::ControlB> = Self::ControlB::WGM11;
    const OCIEA: RegisterBits<Self::InterruptMask> = Self::InterruptMask::OCIE3A;
}

The problem here is that TCCR3A and TCCR3B are missing these RegisterBits:

impl TCCR3A {
    pub const COM3A: RegisterBits<Self> = RegisterBits::new(0xc0);
    pub const COM3A0: RegisterBits<Self> = RegisterBits::new(1<<6);
    pub const COM3A1: RegisterBits<Self> = RegisterBits::new(1<<7);

    pub const COM3B: RegisterBits<Self> = RegisterBits::new(0x30);
    pub const COM3B0: RegisterBits<Self> = RegisterBits::new(1<<4);
    pub const COM3B1: RegisterBits<Self> = RegisterBits::new(1<<5);

    pub const COM3C: RegisterBits<Self> = RegisterBits::new(0xc);
    pub const COM3C0: RegisterBits<Self> = RegisterBits::new(1<<2);
    pub const COM3C1: RegisterBits<Self> = RegisterBits::new(1<<3);

    pub const WGM3: RegisterBits<Self> = RegisterBits::new(0x3);
    pub const WGM30: RegisterBits<Self> = RegisterBits::new(1<<0);
    pub const WGM31: RegisterBits<Self> = RegisterBits::new(1<<1);

}
impl TCCR3B {
    pub const ICNC3: RegisterBits<Self> = RegisterBits::new(0x80);
    pub const ICNC30: RegisterBits<Self> = RegisterBits::new(1<<7);

    pub const ICES3: RegisterBits<Self> = RegisterBits::new(0x40);
    pub const ICES30: RegisterBits<Self> = RegisterBits::new(1<<6);

    pub const WGM3: RegisterBits<Self> = RegisterBits::new(0x18);
    pub const WGM30: RegisterBits<Self> = RegisterBits::new(1<<3);
    pub const WGM31: RegisterBits<Self> = RegisterBits::new(1<<4);

    pub const CS3: RegisterBits<Self> = RegisterBits::new(0x7);
    pub const CS30: RegisterBits<Self> = RegisterBits::new(1<<0);
    pub const CS31: RegisterBits<Self> = RegisterBits::new(1<<1);
    pub const CS32: RegisterBits<Self> = RegisterBits::new(1<<2);

}

This is probably related to the fact that the 16-bit timer's register group is called TC3 in the 32u4.