fae96b17a7
This commit adds support for a new processor RA6M5. It also adds the following classes to the machine module: PWM, DAC, SDCard. Signed-off-by: mbedNoobNinja <novoltage@gmail.com>
439 lines
14 KiB
C
439 lines
14 KiB
C
/*
|
|
* The MIT License (MIT)
|
|
*
|
|
* Copyright (c) 2021 Renesas Electronics Corporation
|
|
* Copyright (c) 2023 Vekatech Ltd.
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
* of this software and associated documentation files (the "Software"), to deal
|
|
* in the Software without restriction, including without limitation the rights
|
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
* copies of the Software, and to permit persons to whom the Software is
|
|
* furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included in
|
|
* all copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
* THE SOFTWARE.
|
|
*/
|
|
|
|
#include <stdbool.h>
|
|
#include "py/mpconfig.h"
|
|
#include "hal_data.h"
|
|
#include "ra_config.h"
|
|
#include "ra_utils.h"
|
|
#include "ra_flash.h"
|
|
|
|
#if !defined(USE_FSP_FLASH)
|
|
#define USE_FSP_FLASH
|
|
#endif
|
|
|
|
#if defined(USE_FSP_FLASH)
|
|
|
|
#if defined(__GNUC__)
|
|
#pragma GCC diagnostic ignored "-Wunused-parameter"
|
|
#pragma GCC diagnostic ignored "-Wmissing-declarations"
|
|
#endif
|
|
|
|
/* Flags, set from Callback function */
|
|
static volatile _Bool g_b_flash_event_not_blank = false;
|
|
static volatile _Bool g_b_flash_event_blank = false;
|
|
static volatile _Bool g_b_flash_event_erase_complete = false;
|
|
static volatile _Bool g_b_flash_event_write_complete = false;
|
|
|
|
static uint8_t flash_buf[FLASH_BUF_SIZE] __attribute__((aligned(2)));
|
|
|
|
#ifdef USE_FSP_QSPI
|
|
#if MICROPY_HW_HAS_QSPI_FLASH
|
|
static bool r_qspi_get_QE(void) {
|
|
/* Enter direct communication mode */
|
|
R_QSPI->SFMCMD = 1U;
|
|
|
|
R_QSPI->SFMCOM = 0x35;
|
|
bool sts = (R_QSPI->SFMCOM >> 1) & 1;
|
|
|
|
/* Close the SPI bus cycle. Reference section 39.10.3 "Generating the SPI Bus Cycle during Direct Communication"
|
|
* in the RA6M3 manual R01UH0886EJ0100. */
|
|
R_QSPI->SFMCMD = 1U;
|
|
|
|
/* Exit direct communication mode */
|
|
R_QSPI->SFMCMD = 0U;
|
|
|
|
return sts;
|
|
}
|
|
|
|
static void r_qspi_set_QE(qspi_instance_ctrl_t *p_instance_ctrl) {
|
|
/* Enter direct communication mode */
|
|
R_QSPI->SFMCMD = 1U;
|
|
|
|
/* Enable write. */
|
|
R_QSPI->SFMCOM = p_instance_ctrl->p_cfg->write_enable_command;
|
|
|
|
/* Close the SPI bus cycle. Reference section 39.10.3 "Generating the SPI Bus Cycle during Direct Communication"
|
|
* in the RA6M3 manual R01UH0886EJ0100. */
|
|
R_QSPI->SFMCMD = 1U;
|
|
|
|
R_QSPI->SFMCOM = 0x31;
|
|
R_QSPI->SFMCOM = 0x02;
|
|
|
|
/* Close the SPI bus cycle. Reference section 39.10.3 "Generating the SPI Bus Cycle during Direct Communication"
|
|
* in the RA6M3 manual R01UH0886EJ0100. */
|
|
R_QSPI->SFMCMD = 1U;
|
|
|
|
/* Exit direct communication mode */
|
|
R_QSPI->SFMCMD = 0U;
|
|
}
|
|
|
|
static void r_qspi_wait_WIP(qspi_instance_ctrl_t *p_instance_ctrl) {
|
|
/* Enter direct communication mode */
|
|
R_QSPI->SFMCMD = 1U;
|
|
|
|
R_QSPI->SFMCOM = p_instance_ctrl->p_cfg->status_command;
|
|
while ((R_QSPI->SFMCOM >> p_instance_ctrl->p_cfg->write_status_bit) & 1) {
|
|
;
|
|
}
|
|
|
|
/* Close the SPI bus cycle. Reference section 39.10.3 "Generating the SPI Bus Cycle during Direct Communication"
|
|
* in the RA6M3 manual R01UH0886EJ0100. */
|
|
R_QSPI->SFMCMD = 1U;
|
|
|
|
/* Exit direct communication mode */
|
|
R_QSPI->SFMCMD = 0U;
|
|
}
|
|
|
|
static fsp_err_t R_QSPI_QuadEnable(spi_flash_ctrl_t *p_ctrl) {
|
|
qspi_instance_ctrl_t *p_instance_ctrl = (qspi_instance_ctrl_t *)p_ctrl;
|
|
|
|
#if QSPI_CFG_PARAM_CHECKING_ENABLE
|
|
FSP_ASSERT(NULL != p_instance_ctrl);
|
|
FSP_ASSERT(NULL != p_status);
|
|
FSP_ERROR_RETURN(QSPI_PRV_OPEN == p_instance_ctrl->open, FSP_ERR_NOT_OPEN);
|
|
|
|
/* Do not enter direct communication mode from XIP mode. Reference note in section 39.10.2 "Using Direct
|
|
* Communication Mode" in the RA6M3 manual R01UH0886EJ0100. */
|
|
FSP_ERROR_RETURN(0U == R_QSPI->SFMSDC_b.SFMXST, FSP_ERR_INVALID_MODE);
|
|
#endif
|
|
|
|
/* Read device status. */
|
|
if (!r_qspi_get_QE()) {
|
|
r_qspi_set_QE(p_instance_ctrl);
|
|
}
|
|
|
|
return FSP_SUCCESS;
|
|
}
|
|
|
|
static fsp_err_t R_QSPI_Wait_WIP(spi_flash_ctrl_t *p_ctrl) {
|
|
qspi_instance_ctrl_t *p_instance_ctrl = (qspi_instance_ctrl_t *)p_ctrl;
|
|
|
|
#if QSPI_CFG_PARAM_CHECKING_ENABLE
|
|
FSP_ASSERT(NULL != p_instance_ctrl);
|
|
FSP_ASSERT(NULL != p_status);
|
|
FSP_ERROR_RETURN(QSPI_PRV_OPEN == p_instance_ctrl->open, FSP_ERR_NOT_OPEN);
|
|
|
|
/* Do not enter direct communication mode from XIP mode. Reference note in section 39.10.2 "Using Direct
|
|
* Communication Mode" in the RA6M3 manual R01UH0886EJ0100. */
|
|
FSP_ERROR_RETURN(0U == R_QSPI->SFMSDC_b.SFMXST, FSP_ERR_INVALID_MODE);
|
|
#endif
|
|
|
|
/* Wait WIP flag to go 0 */
|
|
r_qspi_wait_WIP(p_instance_ctrl);
|
|
|
|
return FSP_SUCCESS;
|
|
}
|
|
|
|
static bool lmemprob(void *dst, size_t len) {
|
|
uint8_t *p;
|
|
for (p = (uint8_t *)dst; ((len > 0) && (p[0] == 0xFF)); len--) {
|
|
p++;
|
|
}
|
|
|
|
return len? false : true;
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
void *FLASH_SECTION lmemset(void *dst, int c, size_t len) {
|
|
char *p;
|
|
for (p = (char *)dst; len > 0; len--) {
|
|
*(p++) = (char)c;
|
|
}
|
|
return (void *)dst;
|
|
}
|
|
|
|
void *FLASH_SECTION lmemcpy(void *dst, const void *src, size_t len) {
|
|
char *d = (char *)dst;
|
|
const char *s = (const char *)src;
|
|
for (; len > 0; len--) {
|
|
*(d++) = *(s++);
|
|
}
|
|
return (void *)dst;
|
|
}
|
|
|
|
int FLASH_SECTION lmemcmp(const void *p1, const void *p2, size_t len) {
|
|
unsigned char *a, *b;
|
|
size_t i;
|
|
|
|
a = (unsigned char *)p1;
|
|
b = (unsigned char *)p2;
|
|
for (i = 0; i < len; i++) {
|
|
if (*a != *b) {
|
|
return (*a < *b) ? -1 : 1;
|
|
}
|
|
a++;
|
|
b++;
|
|
}
|
|
return (int)0;
|
|
}
|
|
|
|
#if defined(RA4M1) | defined(RA4M3) | defined(RA4W1) | MICROPY_HW_HAS_QSPI_FLASH
|
|
|
|
uint32_t FLASH_SECTION sector_size(uint32_t addr) {
|
|
return FLASH_SECTOR_SIZE;
|
|
}
|
|
|
|
uint32_t FLASH_SECTION sector_start(uint32_t addr) {
|
|
return addr & ~(FLASH_SECTOR_SIZE - 1);
|
|
}
|
|
|
|
uint32_t FLASH_SECTION sector_index(uint32_t addr) {
|
|
return (addr - 0x00000000) / FLASH_SECTOR_SIZE;
|
|
}
|
|
|
|
#elif defined(RA6M1) | defined(RA6M2) | defined(RA6M3) | defined(RA6M5)
|
|
|
|
#define REGION1_SECTOR_SIZE 0x8000 // 32K
|
|
#define REGION1_SECTOR_MAX 14
|
|
#define REGION0_SECTOR_SIZE 0x2000 // 8K
|
|
#define REGION0_SECTOR_MAX 8
|
|
|
|
uint32_t FLASH_SECTION sector_size(uint32_t addr) {
|
|
if (addr < 0x00010000) {
|
|
return REGION0_SECTOR_SIZE;
|
|
} else {
|
|
return REGION1_SECTOR_SIZE;
|
|
}
|
|
}
|
|
|
|
uint32_t FLASH_SECTION sector_start(uint32_t addr) {
|
|
if (addr < 0x00010000) {
|
|
return addr & ~(REGION0_SECTOR_SIZE - 1);
|
|
} else {
|
|
return addr & ~(REGION1_SECTOR_SIZE - 1);
|
|
}
|
|
}
|
|
|
|
uint32_t FLASH_SECTION sector_index(uint32_t addr) {
|
|
if (addr < 0x00010000) {
|
|
return (addr - 0x00000000) / REGION0_SECTOR_SIZE;
|
|
} else {
|
|
return ((addr - 0x00010000) / REGION1_SECTOR_SIZE) + REGION0_SECTOR_SIZE;
|
|
}
|
|
}
|
|
|
|
#else
|
|
#error "CMSIS MCU Series is not specified."
|
|
#endif
|
|
|
|
bool internal_flash_read(uint8_t *addr, uint32_t NumBytes, uint8_t *pSectorBuff) {
|
|
CHIP_WORD *startaddr = (CHIP_WORD *)addr;
|
|
CHIP_WORD *endaddr = (CHIP_WORD *)(addr + NumBytes);
|
|
while (startaddr < endaddr) {
|
|
*pSectorBuff++ = *startaddr++;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool internal_flash_write(uint8_t *addr, uint32_t NumBytes, uint8_t *pSectorBuff, bool ReadModifyWrite) {
|
|
return internal_flash_writex(addr, NumBytes, pSectorBuff, ReadModifyWrite, true);
|
|
}
|
|
|
|
bool internal_flash_writex(uint8_t *addr, uint32_t NumBytes, uint8_t *pSectorBuff, bool ReadModifyWrite, bool fIncrementDataPtr) {
|
|
fsp_err_t err = FSP_SUCCESS;
|
|
bool flag;
|
|
uint32_t count;
|
|
uint8_t *buf_addr = (uint8_t *)&flash_buf[0];
|
|
uint32_t startaddr = (uint32_t)addr & FLASH_BUF_ADDR_MASK;
|
|
uint32_t offset = (uint32_t)addr & FLASH_BUF_OFF_MASK;
|
|
uint32_t endaddr = (uint32_t)addr + NumBytes;
|
|
uint32_t error_code = 0;
|
|
while (startaddr < endaddr) {
|
|
// copy from dst rom addr to flash buffer to keep current data
|
|
lmemcpy(flash_buf, (void *)startaddr, FLASH_BUF_SIZE);
|
|
// memset(flash_buf, 0xff, FLASH_BUF_SIZE);
|
|
if (NumBytes + offset > FLASH_BUF_SIZE) {
|
|
count = FLASH_BUF_SIZE - offset;
|
|
NumBytes -= count;
|
|
} else {
|
|
count = NumBytes;
|
|
}
|
|
// overwrite data from src addr to flash buffer
|
|
if (fIncrementDataPtr) {
|
|
lmemcpy(flash_buf + offset, pSectorBuff, count);
|
|
} else {
|
|
lmemset(flash_buf + offset, (int)*pSectorBuff, count);
|
|
}
|
|
g_b_flash_event_write_complete = false;
|
|
uint8_t *flash_addr = (uint8_t *)((uint32_t)startaddr & FLASH_BUF_ADDR_MASK);
|
|
#if MICROPY_HW_HAS_QSPI_FLASH
|
|
for (uint16_t idx = 0; ((err == FSP_SUCCESS) && (idx < FLASH_SECTOR_SIZE)); idx += FLASH_PAGE_SIZE)
|
|
{
|
|
err = R_QSPI_Write(&g_qspi0_ctrl, &buf_addr[idx], &flash_addr[idx], FLASH_PAGE_SIZE);
|
|
err = R_QSPI_Wait_WIP(&g_qspi0_ctrl);
|
|
}
|
|
#else
|
|
uint32_t state = ra_disable_irq();
|
|
#if defined(RA4M1) | defined(RA4M3) | defined(RA4W1)
|
|
err = R_FLASH_LP_Write(&g_flash0_ctrl, (uint32_t const)buf_addr, (uint32_t)flash_addr, FLASH_SECTOR_SIZE);
|
|
#elif defined(RA6M1) | defined(RA6M2) | defined(RA6M3) | defined(RA6M5)
|
|
err = R_FLASH_HP_Write(&g_flash0_ctrl, (uint32_t const)buf_addr, (uint32_t)flash_addr, FLASH_SECTOR_SIZE);
|
|
#else
|
|
#error "CMSIS MCU Series is not specified."
|
|
#endif
|
|
ra_enable_irq(state);
|
|
#endif
|
|
if (FSP_SUCCESS != err) {
|
|
error_code = 1;
|
|
goto WriteX_exit;
|
|
}
|
|
if (fIncrementDataPtr) {
|
|
flag = (lmemcmp((void *)(startaddr + offset), flash_buf + offset, count) == 0);
|
|
if (!flag) {
|
|
error_code = 2;
|
|
break;
|
|
}
|
|
}
|
|
offset = 0;
|
|
startaddr += FLASH_BUF_SIZE;
|
|
pSectorBuff += count;
|
|
}
|
|
WriteX_exit:
|
|
if (error_code == 0) {
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool internal_flash_memset(uint8_t *addr, uint8_t Data, uint32_t NumBytes) {
|
|
return true;
|
|
}
|
|
|
|
bool internal_flash_isblockerased(uint8_t *addr, uint32_t BlockLength) {
|
|
g_b_flash_event_not_blank = false;
|
|
g_b_flash_event_blank = false;
|
|
#if MICROPY_HW_HAS_QSPI_FLASH
|
|
return lmemprob((uint8_t *)((uint32_t)addr & FLASH_BUF_ADDR_MASK), FLASH_SECTOR_SIZE);
|
|
#else
|
|
fsp_err_t err = FSP_SUCCESS;
|
|
flash_result_t blankCheck = FLASH_RESULT_BLANK;
|
|
uint32_t state = ra_disable_irq();
|
|
#if defined(RA4M1) | defined(RA4M3) | defined(RA4W1)
|
|
err = R_FLASH_LP_BlankCheck(&g_flash0_ctrl, (uint32_t const)((uint32_t)addr & FLASH_BUF_ADDR_MASK), FLASH_SECTOR_SIZE, &blankCheck);
|
|
#elif defined(RA6M1) | defined(RA6M2) | defined(RA6M3) | defined(RA6M5)
|
|
err = R_FLASH_HP_BlankCheck(&g_flash0_ctrl, (uint32_t const)((uint32_t)addr & FLASH_BUF_ADDR_MASK), FLASH_SECTOR_SIZE, &blankCheck);
|
|
#else
|
|
#error "CMSIS MCU Series is not specified."
|
|
#endif
|
|
ra_enable_irq(state);
|
|
if (err == FSP_SUCCESS) {
|
|
if (FLASH_RESULT_BLANK == blankCheck) {
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
} else {
|
|
return false;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
bool internal_flash_eraseblock(uint8_t *addr) {
|
|
uint32_t error_code = 0;
|
|
fsp_err_t err = FSP_SUCCESS;
|
|
g_b_flash_event_erase_complete = false;
|
|
#if MICROPY_HW_HAS_QSPI_FLASH
|
|
if (!lmemprob((uint8_t *)((uint32_t)addr & FLASH_BUF_ADDR_MASK), FLASH_SECTOR_SIZE)) {
|
|
err = R_QSPI_Erase(&g_qspi0_ctrl, (uint8_t *const)addr, FLASH_SECTOR_SIZE);
|
|
err = R_QSPI_Wait_WIP(&g_qspi0_ctrl);
|
|
}
|
|
#else
|
|
uint32_t state = ra_disable_irq();
|
|
#if defined(RA4M1) | defined(RA4M3) | defined(RA4W1)
|
|
err = R_FLASH_LP_Erase(&g_flash0_ctrl, (uint32_t const)addr, 1);
|
|
#elif defined(RA6M1) | defined(RA6M2) | defined(RA6M3) | defined(RA6M5)
|
|
err = R_FLASH_HP_Erase(&g_flash0_ctrl, (uint32_t const)addr, 1);
|
|
#else
|
|
#error "CMSIS MCU Series is not specified."
|
|
#endif
|
|
ra_enable_irq(state);
|
|
#endif
|
|
if (err == FSP_SUCCESS) {
|
|
error_code = 0;
|
|
} else {
|
|
error_code = 1;
|
|
}
|
|
if (error_code == 0) {
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/* Callback function */
|
|
void callback_flash(flash_callback_args_t *p_args) {
|
|
/* TODO: add your own code here */
|
|
switch (p_args->event) {
|
|
case FLASH_EVENT_NOT_BLANK:
|
|
g_b_flash_event_not_blank = true;
|
|
break;
|
|
case FLASH_EVENT_BLANK:
|
|
g_b_flash_event_blank = true;
|
|
break;
|
|
case FLASH_EVENT_ERASE_COMPLETE:
|
|
g_b_flash_event_erase_complete = true;
|
|
break;
|
|
case FLASH_EVENT_WRITE_COMPLETE:
|
|
g_b_flash_event_write_complete = true;
|
|
break;
|
|
default:
|
|
/* Do nothing */
|
|
break;
|
|
}
|
|
}
|
|
|
|
bool internal_flash_init(void) {
|
|
fsp_err_t err = FSP_SUCCESS;
|
|
#if MICROPY_HW_HAS_QSPI_FLASH
|
|
err = R_QSPI_Open(&g_qspi0_ctrl, &g_qspi0_cfg);
|
|
if (err == FSP_SUCCESS) {
|
|
R_QSPI_QuadEnable(&g_qspi0_ctrl);
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
#else
|
|
#if defined(RA4M1) | defined(RA4M3) | defined(RA4W1)
|
|
err = R_FLASH_LP_Open(&g_flash0_ctrl, &g_flash0_cfg);
|
|
#elif defined(RA6M1) | defined(RA6M2) | defined(RA6M3) | defined(RA6M5)
|
|
err = R_FLASH_HP_Open(&g_flash0_ctrl, &g_flash0_cfg);
|
|
#else
|
|
#error "CMSIS MCU Series is not specified."
|
|
#endif
|
|
if (err == FSP_SUCCESS) {
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
#else
|
|
|
|
// ToDo: implementation
|
|
|
|
#endif
|