- 2024-12-15
-
发表了主题帖:
【Follow me第二季第3期】任务汇总
本贴是Follow me第二季第3期,所有任务的相关视频、任务内容、代码等内容的汇总帖。具体如下:
一、任务介绍
本次Follow me第二季第3期的活动,主要的硬件环境就是RA的evb板子,具体型号为:EK-RA6M5开发套件。包含一个开发板,一条micro USB数据线,一条网线和一条micro USB转type A接口的数据线。
本次活动主要参考ra官方的《ra-fsp-examples-5.6.0.example.2》示例程序,完成以下四个任务:
入门任务:搭建环境,下载调试示例程序,Blink,按键
基础任务:quad-spi flash和octo-spi flash配置及读写速度测试;DAC配置生成波形正弦波形
进阶任务:示例程序中新增命令打印信息,输出DAC的实时数据
扩展任务:设计一个类似信号发生器功能的例程。通过命令或按键,设置DAC输出波形,可通过flash存储历史波形等信息。
二、具体任务
1. 入门任务
任务链接
》》》【Follow me第二季第3期】 EK-RA6M5 入门任务 《《《
流程图
主要代码片段
控制蓝灯blink的定时器回调函数
void gpt_blue_callback(timer_callback_args_t * p_args)
{
/* Void the unused params */
FSP_PARAMETER_NOT_USED(p_args);
switch (s_blueled_flashing)
{
case ON:
{
if ((s_intense++ ) < s_duty)
{
TURN_BLUE_ON
}
else
{
TURN_BLUE_OFF
}
if (s_intense >= 100)
{
s_intense = 0;
s_duty = g_pwm_dcs[g_board_status.led_intensity];
}
break;
}
default:
{
TURN_BLUE_OFF
s_intense = 0;
s_duty = g_pwm_dcs[g_board_status.led_intensity];
}
}
}
按键控制闪灯亮度的回调函数
void button_irq10_callback(external_irq_callback_args_t *p_args)
{
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
BaseType_t xResult = pdFAIL;
EventBits_t uxBits;
/* Void the unused args */
FSP_PARAMETER_NOT_USED(p_args);
uxBits = xEventGroupGetBitsFromISR (g_update_console_event);
if ((uxBits & (STATUS_UPDATE_INTENSE_INFO)) != (STATUS_UPDATE_INTENSE_INFO))
{
/* Cast, as compiler will assume calc is int */
g_board_status.led_intensity = (uint16_t) ((g_board_status.led_intensity + 1) % 4);
xResult = xEventGroupSetBitsFromISR(g_update_console_event, STATUS_UPDATE_INTENSE_INFO,
&xHigherPriorityTaskWoken);
/* Was the message posted successfully? */
if (pdFAIL != xResult)
{
/* If xHigherPriorityTaskWoken is now set to pdTRUE then a context
switch should be requested. The macro used is port specific and will
be either portYIELD_FROM_ISR() or portEND_SWITCHING_ISR() - refer to
the documentation page for the port being used. */
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}
}
}
按键控制闪灯频率的回调函数
void button_irq9_callback(external_irq_callback_args_t *p_args)
{
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
BaseType_t xResult = pdFAIL;
EventBits_t uxBits;
/* Void the unused args */
FSP_PARAMETER_NOT_USED(p_args);
uxBits = xEventGroupGetBitsFromISR (g_update_console_event);
if ((uxBits & (STATUS_UPDATE_FREQ_INFO)) != (STATUS_UPDATE_FREQ_INFO))
{
/* Cast, as compiler will assume calc is int */
g_board_status.led_frequency = (uint16_t) ((g_board_status.led_frequency + 1) % 4);
xResult = xEventGroupSetBitsFromISR(g_update_console_event, STATUS_UPDATE_FREQ_INFO, &xHigherPriorityTaskWoken);
/* Was the message posted successfully? */
if (pdFAIL != xResult)
{
/* If xHigherPriorityTaskWoken is now set to pdTRUE then a context
switch should be requested. The macro used is port specific and will
be either portYIELD_FROM_ISR() or portEND_SWITCHING_ISR() - refer to
the documentation page for the port being used. */
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}
}
}
设备运行结果
2. 基础任务
任务链接
》》》【Follow me第二季第3期】基础任务 《《《
流程图
FLASH读写速度测试 DAC波形输出
主要代码片段
2.1 OSPI写测试
static uint32_t write_dopi_ospi(uint32_t data_size)
{
fsp_err_t err;
uint32_t test_var;
/* Cast to req type */
uint8_t * p_dest = (uint8_t *)OSPI_DMA_ADDRESS;
timer_status_t status = {};
uint32_t number_of_pages;
R_GPT_Open(g_memory_performance.p_ctrl, g_memory_performance.p_cfg);
/* Cast, as compiler will assume result of calc to be int */
number_of_pages = (uint32_t)(data_size * (1024 / OSPI_TEST_PAGE_SIZE));
/* Write 32 blocks worth of data starting at Block 0
* Block size = 64K, i.e. 2 blocks = 128K of data
* check this comment....... */
for (test_var = 0; test_var < number_of_pages; test_var++ )
{
/* Performance measured around this loop will be slightly lower due to branches and test write-in-progress
* The actual throughput should be measured with direct debugger downloads (not supported by SEGGER yet)*/
R_GPT_Start(g_memory_performance.p_ctrl);
err = R_OSPI_Write(g_ospi.p_ctrl, s_page, p_dest, OSPI_TEST_PAGE_SIZE);
if (FSP_SUCCESS != err)
{
__asm("bkpt");
}
ospi_test_wait_until_wip();
p_dest += OSPI_TEST_PAGE_SIZE;
R_GPT_Stop(g_memory_performance.p_ctrl);
vTaskDelay(1U);
}
R_GPT_StatusGet(g_memory_performance.p_ctrl, &status);
R_GPT_Reset(g_memory_performance.p_ctrl);
R_GPT_Close(g_memory_performance.p_ctrl);
return (status.counter);
}
2.2 OSPI 读测试
static uint32_t read_dopi_ospi(uint32_t data_size)
{
/* Cast to req type */
uint32_t * p_src = (uint32_t *)OSPI_DMA_ADDRESS;
/* Cast to req type */
uint32_t * p_dest = (uint32_t *)s_perf_read;
/* Full bus access, transfer 4 bytes at a time */
timer_status_t status = {};
R_GPT_Open(g_memory_performance.p_ctrl, g_memory_performance.p_cfg);
#ifdef READ_PAGE_BY_PAGE
/* convert to number of mem pages */
number_of_blocks = data_size * ( 1024 / OSPI_TEST_PAGE_SIZE);
while(number_of_blocks--)
{
/* convert page size to number of 32bit reads */
data = (OSPI_TEST_PAGE_SIZE) / 4U;
/* Start timer */
R_GPT_Start(g_memory_performance.p_ctrl);
#ifdef MANUAL_READ
while (data)
{
*p_dest = *p_src;
p_dest++;
p_src++;
data--;
}
#endif
#define READ_MEMCPY
#ifdef READ_MEMCPY
memcpy ( p_dest, p_src, OSPI_TEST_PAGE_SIZE / 4);
p_src += OSPI_TEST_PAGE_SIZE / 4;
p_dest += OSPI_TEST_PAGE_SIZE / 4;
/* Stop timer */
R_GPT_Stop(g_memory_performance.p_ctrl);
vTaskDelay(1U);
#endif
}
#endif /* READ_PAGE_BY_PAGE */
#ifdef READ_AS_SINGLE_BLOCK
/* Start timer */
R_GPT_Start(g_memory_performance.p_ctrl);
R_OSPI_XipEnter(g_ospi.p_ctrl);
memcpy (p_dest, p_src, (data_size * 1024) / 4);
R_OSPI_XipExit(g_ospi.p_ctrl);
/* Stop timer */
R_GPT_Stop(g_memory_performance.p_ctrl);
#endif
R_GPT_StatusGet(g_memory_performance.p_ctrl, &status);
R_GPT_Reset(g_memory_performance.p_ctrl);
R_GPT_Close(g_memory_performance.p_ctrl);
return (status.counter);
}
2.3 QSPI写测试
static uint32_t qspi_write_test(uint32_t block_size)
{
fsp_err_t fsp_err;
uint32_t qspi_write_result = 0;
timer_status_t status = {};
fsp_err_t err = FSP_SUCCESS;
spi_flash_protocol_t current_spi_mode;
/* Convert from kB */
block_size *= 1024;
/* The comms mode is EXTENDED_SPI by default */
current_spi_mode = SPI_FLASH_PROTOCOL_EXTENDED_SPI;
/* initialise the QSPI, and change mode to that set in FSP */
err = qpi_init();
if (FSP_SUCCESS == err)
{
/* The comms mode has changed. So if recovering, this new mode required */
current_spi_mode = g_qspi_cfg.spi_protocol;
}
uint32_t page_write_count = 0;
uint8_t * p_mem_addr;
/* Cast to req type */
p_mem_addr = (uint8_t *)QSPI_DEVICE_START_ADDRESS;
while (((page_write_count * SECTOR_SIZE) < block_size)
&& ( FSP_SUCCESS == err ) )
{
/* Erase Flash for one sector */
err = R_QSPI_Erase(&g_qspi_ctrl, p_mem_addr, SECTOR_SIZE);
if (FSP_SUCCESS != err)
{
sprintf(s_print_buffer, "R_QSPI_Erase Failed\r\n");
}
else
{
err = get_flash_status();
if (FSP_SUCCESS != err)
{
sprintf(s_print_buffer, "Failed to get status for QSPI operation\r\n");
}
/* Verify the erased block data */
uint32_t count;
for (count = 0; count < SECTOR_SIZE; count++ )
{
if (DEFAULT_MEM_VAL != p_mem_addr[count])
{
/* Verification failed, perhaps the ERASE failed */
err = FSP_ERR_NOT_ERASED;
}
}
}
p_mem_addr += SECTOR_SIZE;
page_write_count++;
}
/* Start the test timer */
fsp_err = R_GPT_Start(g_memory_performance.p_ctrl);
/* Handle error */
if (FSP_SUCCESS != fsp_err)
{
/* Fatal error */
SYSTEM_ERROR
}
/* Cast to req type */
p_mem_addr = (uint8_t *)QSPI_DEVICE_START_ADDRESS;
page_write_count = 0;
while (((page_write_count * PAGE_WRITE_SIZE) < block_size)
&& (FSP_SUCCESS == err))
{
if (FSP_SUCCESS == err)
{
/* Write data to QSPI Flash */
/* Each block begins one character shifted along the source text. To avoid regular striping in memory */
err = R_QSPI_Write(&g_qspi_ctrl, &(sp_source[page_write_count]), p_mem_addr, PAGE_WRITE_SIZE);
if (FSP_SUCCESS != err)
{
sprintf(s_print_buffer, "R_QSPI_Write Failed\r\n");
}
else
{
err = get_flash_status();
if (FSP_SUCCESS != err)
{
sprintf(s_print_buffer, "Failed to get status for QSPI operation\r\n");
}
}
}
p_mem_addr += PAGE_WRITE_SIZE;
page_write_count++;
}
/* close QSPI module */
deinit_qspi(current_spi_mode);
fsp_err = R_GPT_Stop(g_memory_performance.p_ctrl);
/* Handle error */
if (FSP_SUCCESS != fsp_err)
{
/* Fatal error */
SYSTEM_ERROR
}
fsp_err = R_GPT_StatusGet(g_memory_performance.p_ctrl, &status);
/* Handle error */
if (FSP_SUCCESS != fsp_err)
{
/* Fatal error */
SYSTEM_ERROR
}
fsp_err = R_GPT_Reset(g_memory_performance.p_ctrl);
/* Handle error */
if (FSP_SUCCESS != fsp_err)
{
/* Fatal error */
SYSTEM_ERROR
}
qspi_write_result = status.counter;
return (qspi_write_result);
}
2.4 QSPI读测试
static uint32_t qspi_read_test(uint32_t block_size)
{
fsp_err_t fsp_err;
fsp_err_t err = FSP_SUCCESS;
uint32_t qspi_read_result = 0;
timer_status_t status = {};
spi_flash_protocol_t current_spi_mode;
uint8_t * p_dma_read_buffer;
uint32_t page_read_count;
uint8_t * p_mem_addr;
/* Convert from kB */
block_size *= 1024;
p_dma_read_buffer = pvPortMalloc(block_size);
if (NULL == p_dma_read_buffer)
{
HeapStats_t pxHeapStats;
vPortGetHeapStats(&pxHeapStats);
sprintf(s_print_buffer, "\r\nQSPI malloc operation Failed - Max free mem: %dbytes\r\n",
pxHeapStats.xSizeOfLargestFreeBlockInBytes);
/* Verification failed, perhaps the ERASE failed */
err = FSP_ERR_NOT_ERASED;
}
/* The comms mode of the FLASH device is EXTENDED_SPI by default */
current_spi_mode = SPI_FLASH_PROTOCOL_EXTENDED_SPI;
/* initialise the QSPI, and change mode to that set in FSP */
err = qpi_init();
if (FSP_SUCCESS == err)
{
/* The comms mode has changed. So if recovering, this new mode required */
current_spi_mode = g_qspi_cfg.spi_protocol;
}
/* Start the test timer */
fsp_err = R_GPT_Start(g_memory_performance.p_ctrl);
/* Handle error */
if (FSP_SUCCESS != fsp_err)
{
/* Fatal error */
SYSTEM_ERROR
}
page_read_count = 0;
/* cast to req type */
p_mem_addr = (uint8_t *)QSPI_DEVICE_START_ADDRESS;
while (((page_read_count * PAGE_WRITE_SIZE) < block_size)
&& (FSP_SUCCESS == err))
{
/* Verify the written data */
/* Each block begins one character shifted along the source text. To avoid regular striping in memory */
if ((fsp_err_t) (memcmp (p_mem_addr, &(sp_source[page_read_count]), PAGE_WRITE_SIZE)) != FSP_SUCCESS)
{
err = FSP_ERR_NOT_ERASED;
sprintf(s_print_buffer, "\r\nQSPI operation Failed -> Data read does not match with written data\r\n");
}
p_mem_addr += PAGE_WRITE_SIZE;
page_read_count++;
}
fsp_err = R_GPT_Stop(g_memory_performance.p_ctrl);
/* close QSPI module */
deinit_qspi(current_spi_mode);
/* Handle error */
if (FSP_SUCCESS != fsp_err)
{
/* Fatal error */
SYSTEM_ERROR
}
fsp_err = R_GPT_StatusGet(g_memory_performance.p_ctrl, &status);
/* Handle error */
if (FSP_SUCCESS != fsp_err)
{
/* Fatal error */
SYSTEM_ERROR
}
fsp_err = R_GPT_Reset(g_memory_performance.p_ctrl);
/* Handle error */
if (FSP_SUCCESS != fsp_err)
{
/* Fatal error */
SYSTEM_ERROR
}
qspi_read_result = status.counter;
vPortFree(p_dma_read_buffer);
return (qspi_read_result);
}
2.5 DAC波形输出
fsp_err_t common_init(void)
{
fsp_err_t fsp_err = FSP_SUCCESS;
fsp_err = adc_initialize ();
if (FSP_SUCCESS != fsp_err)
{
return fsp_err;
}
// DAC初始化
fsp_err = R_DAC_Open(&g_dac0_ctrl, &g_dac0_cfg);
if (FSP_SUCCESS != fsp_err)
{
return fsp_err;
}
// DAC启动
fsp_err = R_DAC_Start(&g_dac0_ctrl);
if (FSP_SUCCESS != fsp_err)
{
return fsp_err;
}
fsp_err = icu_initialize ();
if (FSP_SUCCESS != fsp_err)
{
return fsp_err;
}
fsp_err = gpt_initialize ();
#if 1
if (FSP_SUCCESS != fsp_err)
{
return fsp_err;
}
led_duty_cycle_update ();
#endif
/* Set baseline LED status */
g_board_status.led_intensity = 0;
g_board_status.led_frequency = 0;
R_GPT_PeriodSet(g_blinker.p_ctrl, g_pwm_rates[g_board_status.led_frequency]);
led_duty_cycle_update ();
s_duty = g_pwm_dcs[g_board_status.led_intensity];
/* Start the timers */
R_GPT_Start(g_blinker.p_ctrl);
R_GPT_Start(g_gpt_blue.p_ctrl);
return fsp_err;
}
void gpt_blinker_callback(timer_callback_args_t *p_args)
{
/* Void the unused params */
FSP_PARAMETER_NOT_USED(p_args);
// 计算正弦波
uint16_t dac_val = 0;
static double position = 0.0;
position += (PI / 30); // add 6° per cycle
if (position >= PI*2) // if angle bigger than 90°
position = 0.0;
dac_val = (uint16_t)((sin(position) + 1) / 2 * 4095);
// 通过DAC输出正弦波
R_DAC_Write(&g_dac0_ctrl, dac_val);
if (OFF == s_blueled_flashing)
{
s_blueled_flashing = ON;
}
else
{
s_blueled_flashing = OFF;
}
}
设备运行结果
3. 进阶任务
任务链接
》》》【Follow me第二季第3期】进阶任务《《《
流程图
主要代码片段
test_fn dac_display_menu(void)
{
int8_t c = -1;
uint16_t wn_mcu_temp_f = 0;
uint16_t fr_mcu_temp_f = 0;
uint16_t wn_mcu_temp_c = 0;
uint16_t fr_mcu_temp_c = 0;
sprintf (s_print_buffer, "%s%s", gp_clear_screen, gp_cursor_home);
/* ignoring -Wpointer-sign is OK when treating signed char_t array as as unsigned */
print_to_console((void*)s_print_buffer);
sprintf (s_print_buffer, MODULE_NAME, g_selected_menu);
/* ignoring -Wpointer-sign is OK when treating signed char_t array as as unsigned */
print_to_console((void*)s_print_buffer);
wn_mcu_temp_f = g_board_status.temperature_f.whole_number;
fr_mcu_temp_f = g_board_status.temperature_f.mantissa;
wn_mcu_temp_c = g_board_status.temperature_c.whole_number;
fr_mcu_temp_c = g_board_status.temperature_c.mantissa;
sprintf (s_print_buffer, SUB_OPTIONS, FULL_NAME,
wn_mcu_temp_f, fr_mcu_temp_f, wn_mcu_temp_c, fr_mcu_temp_c,
g_dac_val);
/* ignoring -Wpointer-sign is OK when treating signed char_t array as as unsigned */
print_to_console((void*)s_print_buffer);
sprintf (s_print_buffer, MENU_RETURN_INFO);
/* ignoring -Wpointer-sign is OK when treating signed char_t array as as unsigned */
print_to_console((void*)s_print_buffer);
/* provide small delay so board_status should be up to date */
vTaskDelay (s_ticks_to_wait);
xEventGroupSetBits (g_update_console_event, STATUS_DAC_MONITOR);
}
设备运行结果
4. 扩展任务
任务链接
》》》【Follow me第二季第3期】扩展任务《《《
流程图
主要代码片段
命令行菜单
test_fn dac_display_menu(void)
{
int8_t c = -1;
uint16_t wn_mcu_temp_f = 0;
uint16_t fr_mcu_temp_f = 0;
uint16_t wn_mcu_temp_c = 0;
uint16_t fr_mcu_temp_c = 0;
sprintf (s_print_buffer, "%s%s", gp_clear_screen, gp_cursor_home);
/* ignoring -Wpointer-sign is OK when treating signed char_t array as as unsigned */
print_to_console((void*)s_print_buffer);
sprintf (s_print_buffer, MODULE_NAME, g_selected_menu);
/* ignoring -Wpointer-sign is OK when treating signed char_t array as as unsigned */
print_to_console((void*)s_print_buffer);
wn_mcu_temp_f = g_board_status.temperature_f.whole_number;
fr_mcu_temp_f = g_board_status.temperature_f.mantissa;
wn_mcu_temp_c = g_board_status.temperature_c.whole_number;
fr_mcu_temp_c = g_board_status.temperature_c.mantissa;
sprintf (s_print_buffer, SUB_OPTIONS, FULL_NAME,
wn_mcu_temp_f, fr_mcu_temp_f, wn_mcu_temp_c, fr_mcu_temp_c,
g_dac_val);
/* ignoring -Wpointer-sign is OK when treating signed char_t array as as unsigned */
print_to_console((void*)s_print_buffer);
sprintf (s_print_buffer, MENU_RETURN_INFO);
/* ignoring -Wpointer-sign is OK when treating signed char_t array as as unsigned */
print_to_console((void*)s_print_buffer);
/* provide small delay so board_status should be up to date */
vTaskDelay (s_ticks_to_wait);
xEventGroupSetBits (g_update_console_event, STATUS_DAC_MONITOR);
uint32_t read_data_len = 0;
uint32_t save_len = 0;
while (CONNECTION_ABORT_CRTL != c)
{
c = input_from_console ();
if ((MENU_EXIT_CRTL == c) || (CONNECTION_ABORT_CRTL == c))
{
break;
}
else if ('s' == c)
{
g_dac_write_data_len = 0;
sprintf (s_print_buffer, "%s select: %c start save wave %s", gp_cursor_store, c, gp_cursor_restore);
print_to_console((void*)s_print_buffer);
}
else if ('t' == c)
{
int offset = sprintf (s_print_buffer, "%s select: %c stop save wave. \r\nsave data: \r\n\t", gp_cursor_store, c);
save_len = g_dac_write_data_len;
for (uint16_t i = 0; i < save_len; i++)
{
offset += sprintf (s_print_buffer + offset, "%d ", g_dac_adwrite_data_buff[i]);
}
sprintf (s_print_buffer + offset, " %s", gp_cursor_restore);
print_to_console((void*)s_print_buffer);
qspi_write(save_len * sizeof(uint16_t), g_dac_adwrite_data_buff);
}
else if ('p' == c)
{
sprintf (s_print_buffer, "%s select: %c get wave %s", gp_cursor_store, c, gp_cursor_restore);
print_to_console((void*)s_print_buffer);
qspi_read(&read_data_len, read_data_buff);
int offset = sprintf (s_print_buffer, "get %s length: %d \r\nGet data: \r\n\t", gp_cursor_store, read_data_len/2);
for (uint16_t i = 0; i < read_data_len / 2; i++)
{
offset += sprintf (s_print_buffer + offset, "%d ", read_data_buff[i]);
}
sprintf (s_print_buffer + offset, " %s", gp_cursor_restore);
print_to_console((void*)s_print_buffer);
}
}
xEventGroupClearBits (g_update_console_event, STATUS_DAC_MONITOR);
return (0);
}
缓存DAC值
void gpt_blinker_callback(timer_callback_args_t *p_args)
{
/* Void the unused params */
FSP_PARAMETER_NOT_USED(p_args);
uint16_t dac_val = 0;
static double position = 0.0;
position += (PI / 30); // add 6° per cycle
if (position >= PI*2) // if angle bigger than 90°
position = 0.0;
dac_val = (uint16_t)((sin(position) + 1) / 2 * 4095);
R_DAC_Write(&g_dac0_ctrl, dac_val);
if (OFF == s_blueled_flashing)
{
s_blueled_flashing = ON;
}
else
{
s_blueled_flashing = OFF;
}
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
BaseType_t xResult = pdFAIL;
if (g_dac_val != dac_val)
{
g_dac_val = dac_val;
/* Cast, as compiler will assume calc is int */
xResult = xEventGroupSetBitsFromISR(g_update_console_event, STATUS_DAC_OUTPUT_VAL, &xHigherPriorityTaskWoken);
/* Was the message posted successfully? */
if (pdFAIL != xResult)
{
/* If xHigherPriorityTaskWoken is now set to pdTRUE then a context
switch should be requested. The macro used is port specific and will
be either portYIELD_FROM_ISR() or portEND_SWITCHING_ISR() - refer to
the documentation page for the port being used. */
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}
g_dac_write_data_len = g_dac_write_data_len >= MAX_DAC_WRITE_BUFFER ? 0 : g_dac_write_data_len;
// save new data to buffer
g_dac_adwrite_data_buff[g_dac_write_data_len++] = g_dac_val;
}
}
SPI Flash写入
static uint32_t qspi_write(uint32_t data_size, uint8_t* data)
{
#if 0
fsp_err_t fsp_err;
uint32_t qspi_write_result = 0;
timer_status_t status = {};
fsp_err_t err = FSP_SUCCESS;
spi_flash_protocol_t current_spi_mode;
/* The comms mode is EXTENDED_SPI by default */
current_spi_mode = SPI_FLASH_PROTOCOL_EXTENDED_SPI;
/* initialise the QSPI, and change mode to that set in FSP */
err = qpi_init();
if (FSP_SUCCESS == err)
{
/* The comms mode has changed. So if recovering, this new mode required */
current_spi_mode = g_qspi_cfg.spi_protocol;
}
uint8_t * p_mem_addr;
/* Cast to req type */
p_mem_addr = (uint8_t *)QSPI_DEVICE_START_ADDRESS;
/* Erase Flash for one sector */
err = R_QSPI_Erase(&g_qspi_ctrl, p_mem_addr, SECTOR_SIZE);
if (FSP_SUCCESS != err)
{
sprintf(s_print_buffer, "R_QSPI_Erase Failed\r\n");
}
/* Cast to req type */
p_mem_addr = (uint8_t *)QSPI_DEVICE_START_ADDRESS;
/* Write data to QSPI Flash */
/* Each block begins one character shifted along the source text. To avoid regular striping in memory */
err = R_QSPI_Write(&g_qspi_ctrl, (uint8_t*)&data_size, p_mem_addr, PAGE_WRITE_SIZE);
if (FSP_SUCCESS != err)
{
sprintf(s_print_buffer, "R_QSPI_Write Failed\r\n");
}
/* close QSPI module */
deinit_qspi(current_spi_mode);
qspi_write_result = status.counter;
return (qspi_write_result);
#else
fsp_err_t fsp_err;
uint32_t qspi_write_result = 0;
timer_status_t status = {};
fsp_err_t err = FSP_SUCCESS;
spi_flash_protocol_t current_spi_mode;
if (data == NULL)
{
err = FSP_ERR_NOT_ERASED;
return err;
}
/* Convert from kB */
uint32_t block_size = (data_size / 1024 + 1)*1024;
uint8_t* p_dma_read_buffer = pvPortMalloc(block_size);
if (NULL == p_dma_read_buffer)
{
HeapStats_t pxHeapStats;
vPortGetHeapStats(&pxHeapStats);
sprintf(s_print_buffer, "\r\nQSPI malloc operation Failed - Max free mem: %dbytes\r\n",
pxHeapStats.xSizeOfLargestFreeBlockInBytes);
/* Verification failed, perhaps the ERASE failed */
err = FSP_ERR_NOT_ERASED;
}
memcpy(p_dma_read_buffer, &data_size, sizeof(data_size));
memcpy(p_dma_read_buffer + sizeof(data_size), data, data_size);
/* The comms mode is EXTENDED_SPI by default */
current_spi_mode = SPI_FLASH_PROTOCOL_EXTENDED_SPI;
/* initialise the QSPI, and change mode to that set in FSP */
err = qpi_init();
if (FSP_SUCCESS == err)
{
/* The comms mode has changed. So if recovering, this new mode required */
current_spi_mode = g_qspi_cfg.spi_protocol;
}
uint32_t page_write_count = 0;
uint8_t * p_mem_addr;
/* Cast to req type */
p_mem_addr = (uint8_t *)QSPI_DEVICE_START_ADDRESS;
while (((page_write_count * SECTOR_SIZE) < block_size)
&& ( FSP_SUCCESS == err ) )
{
/* Erase Flash for one sector */
err = R_QSPI_Erase(&g_qspi_ctrl, p_mem_addr, SECTOR_SIZE);
if (FSP_SUCCESS != err)
{
sprintf(s_print_buffer, "R_QSPI_Erase Failed\r\n");
}
else
{
err = get_flash_status();
if (FSP_SUCCESS != err)
{
sprintf(s_print_buffer, "Failed to get status for QSPI operation\r\n");
}
/* Verify the erased block data */
uint32_t count;
for (count = 0; count < SECTOR_SIZE; count++ )
{
if (DEFAULT_MEM_VAL != p_mem_addr[count])
{
/* Verification failed, perhaps the ERASE failed */
err = FSP_ERR_NOT_ERASED;
}
}
}
p_mem_addr += SECTOR_SIZE;
page_write_count++;
}
/* Cast to req type */
p_mem_addr = (uint8_t *)QSPI_DEVICE_START_ADDRESS;
page_write_count = 0;
while (((page_write_count * PAGE_WRITE_SIZE) < block_size)
&& (FSP_SUCCESS == err))
{
if (FSP_SUCCESS == err)
{
/* Write data to QSPI Flash */
/* Each block begins one character shifted along the source text. To avoid regular striping in memory */
// err = R_QSPI_Write(&g_qspi_ctrl, &(qspi_source[page_write_count]), p_mem_addr, PAGE_WRITE_SIZE);
err = R_QSPI_Write(&g_qspi_ctrl, &(p_dma_read_buffer[page_write_count]), p_mem_addr, PAGE_WRITE_SIZE);
if (FSP_SUCCESS != err)
{
sprintf(s_print_buffer, "R_QSPI_Write Failed\r\n");
}
else
{
err = get_flash_status();
if (FSP_SUCCESS != err)
{
sprintf(s_print_buffer, "Failed to get status for QSPI operation\r\n");
}
}
}
p_mem_addr += PAGE_WRITE_SIZE;
page_write_count++;
}
/* close QSPI module */
deinit_qspi(current_spi_mode);
qspi_write_result = status.counter;
vPortFree(p_dma_read_buffer);
return (qspi_write_result);
#endif
}
SPI Flash读取
static uint32_t qspi_read(uint32_t* data_size, uint8_t* data)
{
#if 0
fsp_err_t fsp_err;
fsp_err_t err = FSP_SUCCESS;
uint32_t qspi_read_result = 0;
timer_status_t status = {};
spi_flash_protocol_t current_spi_mode;
uint8_t * p_mem_addr;
/* The comms mode of the FLASH device is EXTENDED_SPI by default */
current_spi_mode = SPI_FLASH_PROTOCOL_EXTENDED_SPI;
/* initialise the QSPI, and change mode to that set in FSP */
err = qpi_init();
if (FSP_SUCCESS == err)
{
/* The comms mode has changed. So if recovering, this new mode required */
current_spi_mode = g_qspi_cfg.spi_protocol;
}
/* cast to req type */
p_mem_addr = (uint8_t *)QSPI_DEVICE_START_ADDRESS;
memcpy(data_size, p_mem_addr, 1);
sprintf(s_print_buffer, "save length: %d", *data_size);
print_to_console((void*)s_print_buffer);
/* close QSPI module */
deinit_qspi(current_spi_mode);
qspi_read_result = status.counter;
return (qspi_read_result);
#else
fsp_err_t fsp_err;
fsp_err_t err = FSP_SUCCESS;
uint32_t qspi_read_result = 0;
timer_status_t status = {};
spi_flash_protocol_t current_spi_mode;
uint8_t * p_dma_read_buffer;
uint32_t page_read_count;
uint8_t * p_mem_addr;
/* Convert from kB */
uint32_t block_size = 2*1024;
p_dma_read_buffer = pvPortMalloc(block_size);
if (NULL == p_dma_read_buffer)
{
HeapStats_t pxHeapStats;
vPortGetHeapStats(&pxHeapStats);
sprintf(s_print_buffer, "\r\nQSPI malloc operation Failed - Max free mem: %dbytes\r\n",
pxHeapStats.xSizeOfLargestFreeBlockInBytes);
/* Verification failed, perhaps the ERASE failed */
err = FSP_ERR_NOT_ERASED;
}
/* The comms mode of the FLASH device is EXTENDED_SPI by default */
current_spi_mode = SPI_FLASH_PROTOCOL_EXTENDED_SPI;
/* initialise the QSPI, and change mode to that set in FSP */
err = qpi_init();
if (FSP_SUCCESS == err)
{
/* The comms mode has changed. So if recovering, this new mode required */
current_spi_mode = g_qspi_cfg.spi_protocol;
}
page_read_count = 0;
/* cast to req type */
p_mem_addr = (uint8_t *)QSPI_DEVICE_START_ADDRESS;
*data_size = *((uint32_t*)p_mem_addr);
memcpy(data, p_mem_addr + 4, *data_size);
while (((page_read_count * PAGE_WRITE_SIZE) < block_size)
&& (FSP_SUCCESS == err))
{
/* Verify the written data */
/* Each block begins one character shifted along the source text. To avoid regular striping in memory */
if ((fsp_err_t) (memcmp (p_mem_addr, &(qspi_source[page_read_count]), PAGE_WRITE_SIZE)) != FSP_SUCCESS)
{
err = FSP_ERR_NOT_ERASED;
sprintf(s_print_buffer, "\r\nQSPI operation Failed -> Data read does not match with written data\r\n");
}
p_mem_addr += PAGE_WRITE_SIZE;
page_read_count++;
}
qspi_read_result = status.counter;
vPortFree(p_dma_read_buffer);
return (qspi_read_result);
#endif
}
设备运行结果
三、任务视频
》》》视频链接《《《
四、任务代码
》》》示例代码链接《《《
五、活动心得
很高兴能够参加本次的活动,最近工作比较忙,拖到最后完成了各个任务。这个开发板资源还是非常的丰富,然后SDK的demo也比较完善,很多值得学习的地方。后续再项目应用中也尝试使用RA系列的芯片。同时也会更过关注这个RA低功耗一些相关的MCU上面。
-
上传了资料:
【Follow me第二季第3期】任务汇总-代码
-
发表了主题帖:
【Follow me第二季第3期】扩展任务
本贴主要是记录最后一个扩展任务:设计一个类似信号发生器功能的例程。可在示例程序上修改。通过命令或按键,设置DAC输出波形,可通过flash存储历史波形等信息。
主要是实现了前面任务中的DAC的正弦波输出,并且将输出的DAC值,也就是波形保存在SQPI Flash里面。掉电之后,也可以正常查看上次保存的记录。
1. 打开进阶任务的示例工程,然后再新增加的DAC输出的菜单中,增加三个指令,接受来之串口终端的输入指令:
's': 开始记录DAC波形数据,'t': 停止记录DAC波形数据,并且保存再Flash中,'p': 读取Flash中保存的DAC波形数据。
2. 使用全局变量缓存当前开始记录的波形:
3. 增加QSPI Flash的数据保存接口和数据读取接口
4. 原有功能中,可以通过按键控制DAC输出波形的频率。
5. 完成相关代码之后,编译下载到开发板。通过xshell窗口终端工具,连接到开发板debug串口。
6. 输入7,再输入s,开始记录数据,按下t,结束保存数据,并且保存到flash;再按下p,输出保存再flash的数据。
以上基本的正弦波信号发生器功能完成,并且可以保存历史的波形数据,以及波形数据的输出。
-
发表了主题帖:
【Follow me第二季第3期】进阶任务
本贴主要记录进阶任务:示例程序中新增命令打印信息。主要是参考demo示例工程中的Kit imformation增加一个DAC实时输出的Value.
具体操作步骤如下:
1. 在示例工程中,找到菜单任务的总入口:main.c文件的main函数。-》》程序员都懂的。。。
2. 找到menu菜单具体输出的地方:
3. 可以找到菜单全局变量的显示和具体入口函数s_menu_items。在这个全局变量新增加注册一个命令行:
{"DAC monitor", dac_display_menu},
4. 参考kis_display_menu函数实现dac_display_menu,并且增加submenu的显示信息,具体如下:包括问题显示和Dac实时输出的数据。
5. 在DAC波形的任务中,增加了一个全局变量保存实时输出的dac value,并且增加两个event标志位,用于刷新DAC的结果和捕获当前子菜单的输入。
6. 在Dac输出地方进行全局数据更新,注意在回调函数里面需要使用带_ISR后缀的接口,否则会出现系统异常。
7. 在刷新显示任务中,收到STATUS_DAC_OUTPUT_VAL标志位event的地方,进行显示的刷新,然后再清除标志位。
8. 以上功能实现已经完成,编译之后,下载到开发板。使用xshell连接开发板的输出串口。可以看到新增加了一个命令行。
9. 输入7,进入子菜单,可以看到实时刷新的温度和DAC的输出。
以上进阶任务就完成了。
-
发表了主题帖:
【Follow me第二季第3期】基础任务
本贴主要是基础任务:“quad-spi flash和octo-spi flash配置及读写速度测试” 和 “DAC配置生成波形及性能测试”。
基本上按照培训的视频步骤,在【ra-fsp-examples-5.6.0.example.2】example例程里面已经实现了该功能。
具体操作步骤如下:
一、quad-spi flash和octo-spi flash配置及读写速度测试
1. 打开e2studio,按照入门的操作,找到Flash测试的串口终端入口函数:ext_display_menu
2. 在红色框选的地方就是ospi和qspi读写测试的函数
3. 编译程序然后在开发板上运行,通过xshell串口工具查看,输入测试的block size, 64kbytes,得到如下结果:
上述结果可以看到,OSPI的写入速度是QSPI的2倍左右,读取速度是6倍左右。
二、DAC配置生成波形及性能测试
1. 在demo工程中,选择configureation.xml配置文件,在Hal/Common Thread中增加一个新的Stacks
2. 选择Analog --> DAC
3. 配置新增加的DAC的属性,主要是输出引脚的选择
4. 此时可以发现配置DAC0的引脚P014有冲突,可以看到具体冲突的选择功能为ADC0
5. 将冲突的ADC0 关闭,配置文件就没有报错了。
6. 在common_init在函数入口,增加DAC的初始化和使能。
7. demo的blue led 闪烁频率控制回调函数里面,增加DAC正弦波输出的函数。
8. 编译执行,然后下载到开发板,打开示波器,将示波器的通道2接入到开发板的P014,注意共地。可以看到输出的波形。
-
加入了学习《【Follow me第二季第3期】EK_RA6M5汇总提交视频》,观看 【Follow me第二季第3期】EK_RA6M5汇总提交视频
- 2024-12-14
-
加入了学习《Follow me 第二季第3期成果视频》,观看 成果展示
- 2024-12-12
-
加入了学习《FollowMe 第二季:3 - EK_RA6M5 开发板入门》,观看 EK-RA6M5 开发板入门
- 2024-12-11
-
加入了学习《【Follow me第二季第3期】扩展任务---EK_RA6M5函数信号发生器》,观看 【Follow me第二季第3期】扩展任务---EK_RA6M5函数信号发生器
-
加入了学习《Follow me第二季第3期演示视频》,观看 Follow me第二季第3期演示视频
- 2024-10-28
-
发表了主题帖:
【Follow me第二季第3期】 EK-RA6M5 入门任务
本帖最后由 HELLO_GCC 于 2024-12-15 12:18 编辑
很幸运,获得了Digikey的Follow me活动入围通知,再次表示非常感谢!下单购买了EK-RA6M5开发套件,后面就是漫长的等待时间了,等了几天拿到开发板。
接着就是开始搭建开发环境、熟悉开发板的相关规格和外设资料,以及基本的功能验证,具体如下。
一、开发环境搭建
1. RA的开发编译环境是多样化的,工具链可以在活动入口地址找到:https://github.com/renesas/fsp/releases/tag/v5.5.0
2. 由于以前开发做嵌入式开发使用过eclipse,并且自带图形界面工具,非常便于开发。因此,我就选择了官方的:e2s,具体下载地址为:https://github.com/renesas/fsp/releases/download/v5.5.0/setup_fsp_v5_5_0_e2s_v2024-07.exe 。
3. 接下来就是一步一步往下进行安装e2studio,如果提示安装驱动,一并安装了。完成之后,就是熟悉的Eclipse界面了。
4. 用套件里面的MicroUSB线,连接到开发板的Debug1口,上电,可以看到LED1闪烁了。
5. 在设备管理器里面,已经识别到开发板自带的Jlink 调试器了。
二、Demo工程调试
1. 新建Demo工程
2. 输入项目名称,进入下一步
3. 选择FSP版本号,开发板类型 EK-RA6M5,以及交叉编译工具链和Debug工具(由于板载了Jlink,就直接选择Jlink ARM工具)
4. 由于是下载到开发板上的,需要选择可执行文件。这里暂时先不用RTOS操作系统。
5. 选择默认的Blink工程,然后就创建完成了。
6. 这下工程就创建完成了,熟悉的main函数又来了。
先编译一下,看下有没有报错。
在最下方看到,0 errors 0 warnings.
7. 那就开始编译下载调试吧,点击那个绿色的小bug
8. 这下就进入到调试界面了,点击两三下这个下一步,就可以开始看到Blink的效果了。
三、示例程序
1. 导入ra-fsp-examples-5.6.0.example.2文件的示例程序,具体路径如下:
2. 打开e2studio,导入工程
4. 选择demo文件夹
5. 打开配置界面
6. 选择blink的定时器配置,可以看到回调函数gpt_blinker_callback
7. 可以看到蓝色灯控制的函数逻辑的回调函数
8. 最后编译程序下载到开发板,通过按键1和按键2可以控制灯光频率和亮度,在调试监控的界面可以看到按键按下时的频率和亮度变化。
9. demo的blink,按键功能就完成了。
- 2024-10-23
-
加入了学习《Follow me 第二季第2期汇总的视频》,观看 Follow me 第二季第2期汇总的视频
-
加入了学习《动手学深度学习V2》,观看 预告