hk32-partial-hal 0.3.1

HK32 partial HAL
use hk32f0301mxxc_pac::{
    flash::regs::IntVecOffset,
    rcc::regs::{Ahbenr, Cir},
    FLASH, RCC,
};

pub enum RccAhbPeriph {
    All,
    GpioD,
    GpioC,
    GpioB,
    GpioA,
    Crc,
    Flitf,
    Sram,
}

pub fn rcc_ahb_clock_cmd(rcc_ahbperiph: RccAhbPeriph, newstate: bool) {
    RCC.ahbenr().modify(|w| match rcc_ahbperiph {
        RccAhbPeriph::All => w.0 = if newstate { 0x5E0055 } else { 0 },
        RccAhbPeriph::GpioD => w.set_iopden(newstate),
        RccAhbPeriph::GpioC => w.set_iopcen(newstate),
        RccAhbPeriph::GpioB => w.set_iopben(newstate),
        RccAhbPeriph::GpioA => w.set_iopaen(newstate),
        RccAhbPeriph::Crc => w.set_crcen(newstate),
        RccAhbPeriph::Flitf => w.set_flitfen(newstate),
        RccAhbPeriph::Sram => w.set_sramen(newstate),
    });
}

pub fn rcc_ahb_clock_all(newstate: bool) {
    let val = if newstate { 0x1E0054 } else { 0 };
    RCC.ahbenr().write_value(Ahbenr(val));
}

pub enum RccApb2Periph {
    SysCfg,
    Adc,
    Tim1,
    Spi,
    Uart1,
    DbgMcu,
}
pub fn rcc_apb2_clock_cmd(rcc_apb2periph: RccApb2Periph, newstate: bool) {
    RCC.apbenr2().modify(|w| match rcc_apb2periph {
        RccApb2Periph::SysCfg => w.set_syscfgen(newstate),
        RccApb2Periph::Adc => w.set_adcen(newstate),
        RccApb2Periph::Tim1 => w.set_tim1en(newstate),
        RccApb2Periph::Spi => w.set_spien(newstate),
        RccApb2Periph::Uart1 => w.set_uart1en(newstate),
        RccApb2Periph::DbgMcu => w.set_dbgmcuen(newstate),
    });
}

pub enum RccApb1Periph {
    Tim2,
    Tim6,
    Wwdg,
    Awu,
    Uart2,
    I2c,
    Pwr,
    IOMUX,
}

pub fn rcc_apb1_clock_cmd(rcc_apb1periph: RccApb1Periph, newstate: bool) {
    RCC.apbenr1().modify(|w| match rcc_apb1periph {
        RccApb1Periph::Tim2 => w.set_tim2en(newstate),
        RccApb1Periph::Tim6 => w.set_tim6en(newstate),
        RccApb1Periph::Wwdg => w.set_wwdgen(newstate),
        RccApb1Periph::Uart2 => w.set_uart2en(newstate),
        RccApb1Periph::I2c => w.set_i2cen(newstate),
        RccApb1Periph::Pwr => w.set_pwren(newstate),
        RccApb1Periph::Awu => w.set_awuen(newstate),
        RccApb1Periph::IOMUX => w.set_iomuxen(newstate),
    });
}

fn sys_set_clock_to_hsi_48m() {
    // /* Enable HSI */
    // RCC->CR |= RCC_CR_HSION;
    RCC.cr().modify(|w| w.set_hsion(true));

    // RCC->CFGR4 &= ~RCC_CFGR4_FLITFCLK_PRE;
    // RCC->CFGR4 |= (((uint32_t)0x07) << RCC_CFGR4_FLITFCLK_PRE_Pos);
    RCC.cfgr4().modify(|w| w.set_flitfclk_pre(0x07));

    // /* Wait till HSI is ready and if Time out is reached exit */
    // do{
    // 	HSIStatus = RCC->CR & RCC_CR_HSIRDY;
    // 	StartUpCounter++;
    // } while((HSIStatus == 0) && (StartUpCounter != STARTUP_TIMEOUT));
    while !RCC.cr().read().hsirdy() {}

    // /* Flash wait state */
    // ACRreg = FLASH->ACR;
    // ACRreg &= (uint32_t)((uint32_t)~FLASH_ACR_LATENCY);
    // FLASH->ACR = (uint32_t)(FLASH_Latency_2|ACRreg);
    FLASH.acr().modify(|w| w.set_latency(0x2));

    // RCCHCLKReg = RCC->CFGR;
    // RCCHCLKReg &= (uint32_t)((uint32_t)~RCC_CFGR_HPRE_Mask);
    // /* HCLK = SYSCLK */
    // RCC->CFGR = (uint32_t)(0|RCCHCLKReg);
    RCC.cfgr().modify(|w| w.set_hpre(0));

    // RCCPCLKReg = RCC->CFGR;
    // RCCPCLKReg &= (uint32_t)((uint32_t)~RCC_CFGR_PPRE_Mask);
    // /* PCLK = HCLK */
    // RCC->CFGR = (uint32_t)(0|RCCPCLKReg);
    RCC.cfgr().modify(|w| w.set_ppre(0));

    // /* Select HSI as system clock source */
    // RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));
    // RCC->CFGR |= (uint32_t)RCC_SYSCLKSource_HSI;
    RCC.cfgr().modify(|w| w.set_sw(0));

    // /* Wait till HSI is used as system clock source */
    // while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != RCC_CFGR_SWS_HSI)
    while RCC.cfgr().read().sws() != 0 {}
}

fn hsi_trimming_value_load() {
    /* load HSI trimming value*/
    unsafe {
        let hsi_value_ptr = 0x1FFFF10C as *const u32;
        let hsi_value = hsi_value_ptr.read();

        // Read current CR register value and mask with 0xFFFFC003
        let mut temp = RCC.cr().read().0 & 0xFFFFC003;

        // Check if the trimming value is valid (checksum verification)
        if (hsi_value & 0xFFFF) == (0xFFFF - ((hsi_value >> 16) & 0xFFFF)) {
            let mut hsical = hsi_value & 0xFF;
            hsical = hsical >> 2;
            let hsitrim = (hsi_value >> 8) & 0xFF;

            temp |= hsitrim << 8;
            temp |= hsical << 2;

            // Write the modified value back to CR register
            RCC.cr().write_value(hk32f0301mxxc_pac::rcc::regs::Cr(temp));
        }
    }
}

fn pmu_trimming_value_load() {
    /* load PMU trimming value*/
    unsafe {
        let bgp_value_ptr = 0x1FFFF114 as *const u32;
        let ldo_value_ptr = 0x1FFFF118 as *const u32;
        let lpldo_value_ptr = 0x1FFFF11C as *const u32;

        let bgp_value = bgp_value_ptr.read();
        let ldo_value = ldo_value_ptr.read();
        let lpldo_value = lpldo_value_ptr.read();

        // Read current PWR_BGP register value and mask with 0xFFFFE0E0
        let pwr_bgp_ptr = 0x40007070 as *mut u32;
        //let mut bgp_temp = (*pwr_bgp_ptr) & 0xFFFFE0E0;

        let lbgp = (bgp_value >> 8) & 0x1F;
        let mbgp = bgp_value & 0x1F;
        let ldo_run_temp = ldo_value & 0xFF;
        let ldo_lpr_temp = (ldo_value >> 8) & 0xFF;
        let lpldo_lpr_temp = (lpldo_value >> 8) & 0xFF;

        // Enable PWR peripheral clock
        RCC.apbenr1().modify(|w| w.set_pwren(true));

        // BGP trimming
        if (bgp_value & 0xFFFF) == (0xFFFF - ((bgp_value >> 16) & 0xFFFF)) {
            let pwr_cr_ptr = 0x4000704C as *mut u32;

            let bgp_temp = (lbgp << 8) | mbgp;

            // Write unlock sequence
            *pwr_cr_ptr = 0x00001985;
            *pwr_cr_ptr = 0x00000429;

            // Write BGP trimming value
            *pwr_bgp_ptr = bgp_temp;

            // Lock the register
            *pwr_cr_ptr = 0x0000FFFF;
            *pwr_cr_ptr = 0x0000FFFF;
        }

        // LDO_RUN trimming
        if (ldo_value & 0xFFFF) == (0xFFFF - ((ldo_value >> 16) & 0xFFFF)) {
            let pwr_cr_ptr = 0x4000704C as *mut u32;
            let pwr_ldo_run_ptr = 0x40007060 as *mut u32;
            let pwr_ldo_lpr_ptr = 0x40007064 as *mut u32;

            // Write unlock sequence
            *pwr_cr_ptr = 0x00001985;
            *pwr_cr_ptr = 0x00000429;

            // Write LDO trimming values
            *pwr_ldo_run_ptr = ldo_run_temp;
            *pwr_ldo_lpr_ptr = ldo_lpr_temp;

            // Lock the register
            *pwr_cr_ptr = 0x0000FFFF;
            *pwr_cr_ptr = 0x0000FFFF;
        }

        // LPLDO_LPR trimming
        if ((lpldo_value >> 8) & 0xFF) == (0xFF - ((lpldo_value >> 24) & 0xFF)) {
            let pwr_cr_ptr = 0x4000704C as *mut u32;
            let pwr_lpldo_lpr_ptr = 0x4000706C as *mut u32;

            // Write unlock sequence
            *pwr_cr_ptr = 0x00001985;
            *pwr_cr_ptr = 0x00000429;

            // Write LPLDO trimming value
            *pwr_lpldo_lpr_ptr = lpldo_lpr_temp;

            // Lock the register
            *pwr_cr_ptr = 0x0000FFFF;
            *pwr_cr_ptr = 0x0000FFFF;
        }
    }
}

pub fn sys_init(vect_tab_offset: u32) {
    // /* Set HSION bit */
    // RCC->CR |= (uint32_t)0x00000001;
    RCC.cr().modify(|w| w.set_hsion(true));

    // /* Reset SW[1:0], HPRE[3:0], PPRE[2:0] and MCOSEL[2:0] bits */
    // RCC->CFGR &= (uint32_t)0xF8FFB81C;
    RCC.cfgr().modify(|w| w.set_hpre(0));
    RCC.cfgr().modify(|w| w.set_ppre(0));
    RCC.cfgr().modify(|w| w.set_mco(0));
    RCC.cfgr().modify(|w| w.set_sw(0));

    // /* Reset USARTSW[1:0], I2CSW bits */
    // RCC->CFGR3 &= (uint32_t)0xFFFFFFEC;
    RCC.cfgr3().modify(|w| w.set_uart1sw(0));
    RCC.cfgr3().modify(|w| w.set_uart2sw(0));
    RCC.cfgr3().modify(|w| w.set_i2csw(false));

    // /* Disable all interrupts */
    // RCC->CIR = 0x00000000;
    RCC.cir().write_value(Cir(0));

    // FLASH->INT_VEC_OFFSET = VECT_TAB_OFFSET ; /* Vector Table Relocation in Internal FLASH. */
    FLASH
        .int_vec_offset()
        .write_value(IntVecOffset(vect_tab_offset));

    hsi_trimming_value_load();
    pmu_trimming_value_load();
    /* Configure the System clock frequency, AHB/APBx prescalers and Flash settings */
    sys_set_clock_to_hsi_48m();
}