int up_progmem_erasepage(uint16_t page) { uint32_t addr; uint16_t count; if (page >= STM32_FLASH_NPAGES) return -EFAULT; /* Get flash ready and begin erasing single page */ if ( !(getreg32(STM32_RCC_CR) & RCC_CR_HSION) ) return -EPERM; stm32_flash_unlock(); modifyreg32(STM32_FLASH_CR, 0, FLASH_CR_PER); putreg32(page * STM32_FLASH_PAGESIZE, STM32_FLASH_AR); modifyreg32(STM32_FLASH_CR, 0, FLASH_CR_STRT); while( getreg32(STM32_FLASH_SR) & FLASH_SR_BSY ) up_waste(); modifyreg32(STM32_FLASH_CR, FLASH_CR_PER, 0); /* Verify */ for (addr = page * STM32_FLASH_PAGESIZE + STM32_FLASH_BASE, count = STM32_FLASH_PAGESIZE; count; count-=4, addr += 4) { if (getreg32(addr) != 0xFFFFFFFF) return -EIO; } return STM32_FLASH_PAGESIZE; }
void stm32_rcc_enablelse(void) { /* The LSE is in the RTC domain and write access is denied to this domain * after reset, you have to enable write access using DBP bit in the PWR CR * register before to configuring the LSE. */ stm32_pwr_enablebkp(true); #if defined(CONFIG_STM32_STM32L15XX) /* Enable the External Low-Speed (LSE) oscillator by setting the LSEON bit * the RCC CSR register. */ modifyreg32(STM32_RCC_CSR, 0, RCC_CSR_LSEON); /* Wait for the LSE clock to be ready */ while ((getreg32(STM32_RCC_CSR) & RCC_CSR_LSERDY) == 0) { up_waste(); } #else /* Enable the External Low-Speed (LSE) oscillator by setting the LSEON bit * the RCC BDCR register. */ modifyreg16(STM32_RCC_BDCR, 0, RCC_BDCR_LSEON); /* Wait for the LSE clock to be ready */ while ((getreg16(STM32_RCC_BDCR) & RCC_BDCR_LSERDY) == 0) { up_waste(); } #endif /* Disable backup domain access if it was disabled on entry */ stm32_pwr_enablebkp(false); }
void stm32_flash_unlock(void) { while( getreg32(STM32_FLASH_SR) & FLASH_SR_BSY ) up_waste(); if ( getreg32(STM32_FLASH_CR) & FLASH_CR_LOCK ) { /* Unlock sequence */ putreg32(FLASH_KEY1, STM32_FLASH_KEYR); putreg32(FLASH_KEY2, STM32_FLASH_KEYR); } }
/** * \todo Check for LSE good timeout and return with -1, * possible ISR optimization? or at least ISR should be cough in case of failure */ void stm32_rcc_enablelse(void) { /* Enable LSE */ modifyreg16(STM32_RCC_BDCR, 0, RCC_BDCR_LSEON); /* We could wait for ISR here ... */ while( !(getreg16(STM32_RCC_BDCR) & RCC_BDCR_LSERDY) ) up_waste(); /* Select LSE as RTC Clock Source */ modifyreg16(STM32_RCC_BDCR, RCC_BDCR_RTCSEL_MASK, RCC_BDCR_RTCSEL_LSE); /* Enable Clock */ modifyreg16(STM32_RCC_BDCR, 0, RCC_BDCR_RTCEN); }
int up_progmem_write(uint32_t addr, const void *buf, size_t count) { uint16_t *hword = (uint16_t *)buf; size_t written = count; /* STM32 requires half-word access */ if (count & 1) return -EINVAL; /* Check for valid address range */ if ( (addr+count) >= STM32_FLASH_SIZE) return -EFAULT; /* Get flash ready and begin flashing */ if ( !(getreg32(STM32_RCC_CR) & RCC_CR_HSION) ) return -EPERM; stm32_flash_unlock(); modifyreg32(STM32_FLASH_CR, 0, FLASH_CR_PG); for (addr += STM32_FLASH_BASE; count; count--, hword++, addr+=2) { /* Write half-word and wait to complete */ putreg16(*hword, addr); while( getreg32(STM32_FLASH_SR) & FLASH_SR_BSY ) up_waste(); /* Verify */ if (getreg32(STM32_FLASH_SR) & FLASH_SR_WRPRT_ERR) { modifyreg32(STM32_FLASH_CR, FLASH_CR_PG, 0); return -EROFS; } if (getreg16(addr) != *hword) { modifyreg32(STM32_FLASH_CR, FLASH_CR_PG, 0); return -EIO; } } modifyreg32(STM32_FLASH_CR, FLASH_CR_PG, 0); return written; }
void stm32_spi2select(FAR struct spi_dev_s *dev, enum spi_dev_e devid, bool selected) { spidbg("devid: %d CS: %s\n", (int)devid, selected ? "assert" : "de-assert"); if (devid == SPIDEV_WIRELESS) { stm32_gpiowrite(GPIO_CC1101_CS, !selected); /* Wait for MISO to go low, indicates that Quart has stabilized */ if (selected) { while( stm32_gpioread(GPIO_SPI2_MISO) ) up_waste(); } } }
static void flash_unlock(uintptr_t base) { while ((getreg32(base + STM32_FLASH_SR_OFFSET) & FLASH_SR_BSY) != 0) { up_waste(); } if ((getreg32(base + STM32_FLASH_CR_OFFSET) & FLASH_CR_LOCK) != 0) { /* Unlock sequence */ putreg32(FLASH_KEY1, base + STM32_FLASH_KEYR_OFFSET); putreg32(FLASH_KEY2, base + STM32_FLASH_KEYR_OFFSET); } }
ssize_t up_progmem_write(size_t addr, const void *buf, size_t count) { uintptr_t base; uint16_t *hword = (uint16_t *)buf; size_t written = count; #if defined(STM32_FLASH_DUAL_BANK) /* Handle paged FLASH */ if (page >= STM32_FLASH_BANK0_NPAGES) { base = STM32_FLASH_BANK1_BASE; } else #endif { base = STM32_FLASH_BANK0_BASE; } /* STM32 requires half-word access */ if (count & 1) { return -EINVAL; } /* Check for valid address range */ if (addr >= STM32_FLASH_BASE) { addr -= STM32_FLASH_BASE; } if ((addr+count) > STM32_FLASH_SIZE) { return -EFAULT; } sem_lock(); if ((getreg32(base + STM32_RCC_CR_OFFSET) & RCC_CR_HSION) == 0) { sem_unlock(); return -EPERM; } /* Get flash ready and begin flashing */ flash_unlock(base); modifyreg32(base + STM32_FLASH_CR_OFFSET, 0, FLASH_CR_PG); for (addr += STM32_FLASH_BASE; count; count -= 2, hword++, addr += 2) { /* Write half-word and wait to complete */ putreg16(*hword, addr); while ((getreg32(base + STM32_FLASH_SR_OFFSET) & FLASH_SR_BSY) != 0) { up_waste(); } /* Verify */ if ((getreg32(base + STM32_FLASH_SR_OFFSET) & FLASH_SR_WRPRT_ERR) != 0) { modifyreg32(base + STM32_FLASH_CR_OFFSET, FLASH_CR_PG, 0); sem_unlock(); return -EROFS; } if (getreg16(addr) != *hword) { modifyreg32(base + STM32_FLASH_CR_OFFSET, FLASH_CR_PG, 0); sem_unlock(); return -EIO; } } modifyreg32(base + STM32_FLASH_CR_OFFSET, FLASH_CR_PG, 0); sem_unlock(); return written; }
ssize_t up_progmem_eraseblock(size_t block) { uintptr_t base; size_t page_address; if (block >= STM32_FLASH_NPAGES) { return -EFAULT; } #if defined(STM32_FLASH_DUAL_BANK) /* Handle paged FLASH */ if (block >= STM32_FLASH_BANK0_NPAGES) { base = STM32_FLASH_BANK1_BASE; } else #endif { base = STM32_FLASH_BANK0_BASE; } sem_lock(); if ((getreg32(base + STM32_RCC_CR_OFFSET) & RCC_CR_HSION) == 0) { sem_unlock(); return -EPERM; } /* Get flash ready and begin erasing single page */ flash_unlock(base); modifyreg32(base + STM32_FLASH_CR_OFFSET, 0, FLASH_CR_PER); /* Must be valid - page index checked above */ page_address = up_progmem_getaddress(block); putreg32(page_address, base + STM32_FLASH_AR_OFFSET); modifyreg32(base + STM32_FLASH_CR_OFFSET, 0, FLASH_CR_STRT); while ((getreg32(base + STM32_FLASH_SR_OFFSET) & FLASH_SR_BSY) != 0) { up_waste(); } modifyreg32(base + STM32_FLASH_CR_OFFSET, FLASH_CR_PER, 0); sem_unlock(); /* Verify */ if (up_progmem_ispageerased(block) == 0) { return up_progmem_erasesize(block); /* success */ } else { return -EIO; /* failure */ } }