add dnr
This commit is contained in:
Binary file not shown.
Binary file not shown.
@@ -137,7 +137,7 @@ set(APP_COMPILER_FLAGS_ex3d_71_all ${SW_USB_AUDIO_FLAGS} -DI2S_CHANS_DAC=2
|
||||
-DMAX_FREQ=48000
|
||||
-DUSE_EX3D
|
||||
-DMIXER=0
|
||||
-DAIZIP_DNR=0 -ldnr_50ms
|
||||
-ldnr_11ms
|
||||
-llib_ex3d_all
|
||||
-DEQ_EN=1
|
||||
-DEX3D_SF_NUM=3
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
// Copyright 2011-2023 XMOS LIMITED.
|
||||
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||
|
||||
|
||||
void agc_init_interface(void);
|
||||
|
||||
|
||||
@@ -10,33 +10,39 @@
|
||||
#include <xcore/chanend.h>
|
||||
#include <xcore/channel.h>
|
||||
#include "xc_ptr.h"
|
||||
#include "dnr_dsp_buf.h"
|
||||
|
||||
#include "xua_conf.h"
|
||||
|
||||
#include "share_buffer.h"
|
||||
|
||||
void buffer_exchange(chanend_t c_data, unsigned sampsFromUsbToAudio[]) {
|
||||
#if EQ_EN
|
||||
chan_out_buf_word (c_data, sampsFromUsbToAudio, 2) ;
|
||||
void dnr_exchange_buffer(int32_t *data);
|
||||
void buffer_exchange(chanend_t c_data, unsigned sampsFromUsbToAudio[], unsigned sampsFromAudioToUsb[]) {
|
||||
chan_out_buf_word (c_data, sampsFromUsbToAudio, 2);
|
||||
chan_out_buf_word (c_data, sampsFromAudioToUsb, 2);
|
||||
chan_in_buf_word (c_data , sampsFromUsbToAudio, 2);
|
||||
#endif
|
||||
chan_in_buf_word (c_data , sampsFromAudioToUsb, 2);
|
||||
}
|
||||
|
||||
void dsp_main (chanend_t c_data) {
|
||||
|
||||
#if EQ_EN
|
||||
int input[NUM_USB_CHAN_OUT];
|
||||
int output[I2S_CHANS_DAC];
|
||||
void dsp_main (chanend_t c_data) {
|
||||
int play_input[NUM_USB_CHAN_OUT];
|
||||
int play_output[I2S_CHANS_DAC];
|
||||
int mic_input[NUM_USB_CHAN_IN];
|
||||
int mic_output[I2S_CHANS_ADC];
|
||||
int count = 0;
|
||||
unsigned ch[1] = {2};
|
||||
while (1) {
|
||||
chan_in_buf_word (c_data , input, 2) ;
|
||||
chan_out_buf_word (c_data , output, I2S_CHANS_DAC);
|
||||
write_to_ring_buffer(0, input[0]);
|
||||
write_to_ring_buffer(1, input[1]);
|
||||
output[0] = read_from_ring_buffer(2);
|
||||
output[1] = read_from_ring_buffer(3);
|
||||
chan_in_buf_word (c_data , play_input, 2) ;
|
||||
chan_in_buf_word (c_data , mic_input, 2) ;
|
||||
chan_out_buf_word (c_data , play_output, I2S_CHANS_DAC);
|
||||
chan_out_buf_word (c_data , mic_output, I2S_CHANS_ADC);
|
||||
write_to_ring_buffer(0, play_input[0]);
|
||||
write_to_ring_buffer(1, play_input[1]);
|
||||
play_output[0] = read_from_ring_buffer(2);
|
||||
play_output[1] = read_from_ring_buffer(3);
|
||||
dnr_exchange_buffer(mic_input);
|
||||
mic_output[0] = mic_input[0];
|
||||
mic_output[1] = mic_input[1];
|
||||
// dnr_exchange_buffer((int32_t *)mic_input, (int32_t *)mic_output);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
#ifndef AZP_H_
|
||||
#define AZP_H_
|
||||
|
||||
|
||||
#include "stdint.h"
|
||||
|
||||
typedef enum
|
||||
{
|
||||
errAZP_NoError = 0, // No error
|
||||
errAZP_NotReady, // Not ready
|
||||
errAZP_InvalidParam, // Invalid parameter
|
||||
errAZP_InvalidLicense, // Invalid license
|
||||
errAZP_BufferOverflow, // Buffer overflow
|
||||
errAZP_BufferTooSmall, // Buffer too small
|
||||
} AZP_STATUS;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int8_t *buffer1; // Pointer to the first buffer
|
||||
int8_t *buffer2; // Pointer to the second buffer
|
||||
int32_t buffer1_size; // Size of the first buffer
|
||||
int32_t buffer2_size; // Size of the second buffer
|
||||
int32_t sample_rate; // Sample rate, only support 16000Hz
|
||||
} azp_dnr_param_t;
|
||||
|
||||
/// @brief DNR initialization
|
||||
/// @param param Configuration parameters
|
||||
/// @return License status
|
||||
/// @brief DNR initialization
|
||||
/// @param param Configuration parameters
|
||||
/// @return License status
|
||||
AZP_STATUS AI_DNR_init(azp_dnr_param_t *param);
|
||||
|
||||
/// @brief DNR processing
|
||||
/// @param audio Q31 input and output
|
||||
/// @return License status
|
||||
AZP_STATUS AI_DNR_Processing(int32_t *audio);
|
||||
|
||||
/// @brief Get version number
|
||||
/// @return If not licensed, returns NULL
|
||||
char *AI_DNR_Version();
|
||||
|
||||
/// @brief Get the size of the working buffers
|
||||
/// @param buf_size Size of the first buffer
|
||||
/// @param buf_size2 Size of the second buffer
|
||||
void getBufferSize(int32_t *buf_size, int32_t *buf_size2);
|
||||
|
||||
/// @brief Set the noise reduction depth
|
||||
/// @param dB Range (-200 to 0 dB)
|
||||
/// -200: Maximum noise reduction
|
||||
/// 0: No noise reduction
|
||||
void setNoisy_mix_factor(float dB);
|
||||
|
||||
|
||||
#endif // AZP_H_
|
||||
@@ -0,0 +1,52 @@
|
||||
// Copyright 2016-2021 XMOS LIMITED.
|
||||
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||
|
||||
#if UART_DEBUG || DEBUG_MEMORY_LOG_ENABLED
|
||||
#define DEBUG_PRINT_ENABLE 1
|
||||
#endif
|
||||
|
||||
#include <xs1.h>
|
||||
#include <xua_conf.h>
|
||||
#include "ringbuf.h"
|
||||
#include <xcore/chanend.h>
|
||||
#include <xcore/channel.h>
|
||||
#include "dnr_dsp_buf.h"
|
||||
#include "xc_ptr.h"
|
||||
#include "debug_print.h"
|
||||
|
||||
unsigned g_dsp_eof = 0;
|
||||
void dnr_exchange_buffer(int32_t *data) {
|
||||
static unsigned buff_index = 0;
|
||||
write_to_sample_in_buf(data[1], buff_index, 0);
|
||||
read_from_sample_out_buf(&data[1],buff_index, 0);
|
||||
data[0] = data[1];
|
||||
|
||||
buff_index++;
|
||||
#if DNR_11MS
|
||||
if (buff_index == 128)
|
||||
{
|
||||
#else
|
||||
if (buff_index == 512)
|
||||
{
|
||||
#endif
|
||||
buf_slot_rotate();
|
||||
buff_index = 0;
|
||||
SET_SHARED_GLOBAL(g_dsp_eof, 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Aizip_DNR_init(void);
|
||||
|
||||
void dnr_dsp_proc_task(void)
|
||||
{
|
||||
Aizip_DNR_init();
|
||||
while(1) {
|
||||
unsigned dsp_eof = 0;
|
||||
GET_SHARED_GLOBAL(dsp_eof, g_dsp_eof);
|
||||
if (dsp_eof) {
|
||||
SET_SHARED_GLOBAL(g_dsp_eof, 0);
|
||||
start_dsp_processing();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
// Copyright 2011-2023 XMOS LIMITED.
|
||||
//
|
||||
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||
|
||||
#if UART_DEBUG || DEBUG_MEMORY_LOG_ENABLED
|
||||
#define DEBUG_PRINT_ENABLE 1
|
||||
#endif
|
||||
|
||||
#include <xs1.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <platform.h>
|
||||
#include <string.h>
|
||||
#include "dnr_dsp_buf.h"
|
||||
#include "aizip_dnr.h"
|
||||
#include "debug_print.h"
|
||||
#include "flash.h"
|
||||
|
||||
//for AGC
|
||||
//static agc_stage_ctx_t DWORD_ALIGNED agc_stage_state = {};
|
||||
|
||||
static unsigned __attribute__((aligned (4))) dsp_dnr_frame_buf[BUF_SLOT_NUM][DSP_CH_NUM][DNR_DSP_FRAME_SIZE];
|
||||
|
||||
unsigned sample_in_buf_slot=0;
|
||||
unsigned processing_buf_slot=2;
|
||||
unsigned sample_out_buf_slot=1;
|
||||
|
||||
|
||||
void dsp_buf_init()
|
||||
{
|
||||
sample_in_buf_slot=0;
|
||||
sample_out_buf_slot=1;
|
||||
processing_buf_slot=2;
|
||||
}
|
||||
|
||||
static void buf_slot_inc(unsigned* buf_slot_input)
|
||||
{
|
||||
if(*buf_slot_input == BUF_SLOT_NUM-1){
|
||||
*buf_slot_input = 0;
|
||||
}
|
||||
else{
|
||||
*buf_slot_input = *buf_slot_input+1;
|
||||
}
|
||||
}
|
||||
|
||||
void buf_slot_rotate()
|
||||
{
|
||||
buf_slot_inc(&sample_in_buf_slot);
|
||||
buf_slot_inc(&sample_out_buf_slot);
|
||||
buf_slot_inc(&processing_buf_slot);
|
||||
}
|
||||
|
||||
void write_to_sample_in_buf(unsigned data, unsigned index, unsigned ch)
|
||||
{
|
||||
dsp_dnr_frame_buf[sample_in_buf_slot][ch][index]=data;
|
||||
}
|
||||
|
||||
void read_from_sample_out_buf(unsigned* read_data, unsigned index, unsigned ch)
|
||||
{
|
||||
*read_data = dsp_dnr_frame_buf[sample_out_buf_slot][ch][index];
|
||||
}
|
||||
#if DNR_11MS
|
||||
int8_t buffer[4208] __attribute__((aligned(4)));
|
||||
int8_t buffer2[31136] __attribute__((aligned(4)));
|
||||
#else
|
||||
int8_t buffer[21416] __attribute__((aligned(4)));
|
||||
int8_t buffer2[31712] __attribute__((aligned(4)));
|
||||
#endif
|
||||
azp_dnr_param_t pram = {
|
||||
.buffer1 = buffer,
|
||||
.buffer1_size = sizeof(buffer),
|
||||
.buffer2 = buffer2,
|
||||
.buffer2_size = sizeof(buffer2),
|
||||
.sample_rate = 48000};
|
||||
|
||||
unsigned g_dnr_init_flag = 0;
|
||||
void Aizip_DNR_init(void)
|
||||
{
|
||||
delay_microseconds(10000);
|
||||
// setFlashPortPins(XS1_PORT_1B,XS1_PORT_1C,XS1_PORT_4B, XS1_CLKBLK_3);
|
||||
|
||||
int sta = AI_DNR_init(&pram);
|
||||
g_dnr_init_flag = 1;
|
||||
debug_printf("AI_DNR_init status %d\n", sta);
|
||||
}
|
||||
|
||||
void start_dsp_processing(void)
|
||||
{
|
||||
float level = -200;
|
||||
|
||||
setNoisy_mix_factor(level);
|
||||
|
||||
AI_DNR_Processing((int32_t *)&dsp_dnr_frame_buf[processing_buf_slot][0][0]);
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
// Copyright 2011-2023 XMOS LIMITED.
|
||||
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||
#ifndef __DNR_DSP_BUF_H__
|
||||
#define __DNR_DSP_BUF_H__
|
||||
|
||||
#include <xs1.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <platform.h>
|
||||
#include <xcore/chanend.h>
|
||||
#include <xcore/channel.h>
|
||||
#if DNR_11MS
|
||||
#define DNR_DSP_FRAME_SIZE 128
|
||||
#else
|
||||
#define DNR_DSP_FRAME_SIZE 512
|
||||
#endif
|
||||
#define BUF_SLOT_NUM 3 //one for input, one for output, one for processing
|
||||
#define DSP_CH_NUM 2
|
||||
|
||||
#if __XC__
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void dnr_set_chan(chanend_t dnr_tile0_c, chanend_t dnr_tile1_c);
|
||||
|
||||
void dsp_buf_init();
|
||||
void buf_slot_rotate();
|
||||
void write_to_sample_in_buf(unsigned data, unsigned index, unsigned ch);
|
||||
void read_from_sample_out_buf(unsigned* read_data, unsigned index, unsigned ch);
|
||||
|
||||
void start_dsp_processing(void);
|
||||
void Aizip_DNR_init(void);
|
||||
|
||||
#if __XC__
|
||||
} //extern c
|
||||
#endif
|
||||
#endif //RINGBUFFER_H
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
#ifndef __FLASH_H__
|
||||
#define __FLASH_H__
|
||||
#include "stdint.h"
|
||||
void setFlashPortPins(uint32_t cs,uint32_t sclk,uint32_t sio,uint32_t clkblk);
|
||||
#endif
|
||||
@@ -0,0 +1,45 @@
|
||||
// Copyright 2011-2023 XMOS LIMITED.
|
||||
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||
#ifndef __RINGBUF_H__
|
||||
#define __RINGBUF_H__
|
||||
|
||||
#include <xs1.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <platform.h>
|
||||
|
||||
#if __XC__
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define FRAME_SIZE 120 //101623 - from 256 to 120
|
||||
|
||||
#define RF_CHAN_NUM 2 //stereo. Multichannel uses NUM_USB_CHAN_OUT
|
||||
//
|
||||
#define RB_SIZE FRAME_SIZE*RF_CHAN_NUM*16 //2 channel, 32-bit, 16 frame
|
||||
#define RB_MASK (RB_SIZE - 1)
|
||||
|
||||
|
||||
extern uint32_t r_buffer[RB_SIZE];
|
||||
|
||||
typedef struct {
|
||||
uint32_t * buf_addr;
|
||||
int next_empty;
|
||||
int next_data;
|
||||
int full;
|
||||
int empty;
|
||||
} ring_buffer_t;
|
||||
|
||||
void rb_init(void);
|
||||
void rb_put_word(uint32_t data);
|
||||
uint32_t rb_get_word(void);
|
||||
int rb_is_full(void);
|
||||
int rb_is_empty(void);
|
||||
|
||||
#if __XC__
|
||||
} //extern c
|
||||
#endif
|
||||
|
||||
#endif //RINGBUFFER_H
|
||||
|
||||
@@ -142,7 +142,7 @@ void UserBufferManagementInit(unsigned sampFreq)
|
||||
}
|
||||
float fLevel[NUM_USB_CHAN_OUT] = {0,};
|
||||
enum {UBM_A3D_OFF=0, UBM_A3D_VON=1, UBM_A3D_ON=2};
|
||||
extern void buffer_exchange(chanend_t c_data, unsigned sampsFromUsbToAudio[]);
|
||||
extern void buffer_exchange(chanend_t c_data, unsigned sampsFromUsbToAudio[], unsigned sampsFromAudioToUsb[]);
|
||||
extern unsigned int is_eq_disabled(void);
|
||||
void UserBufferManagement(unsigned sampsFromUsbToAudio[], unsigned sampsFromAudioToUsb[])
|
||||
{
|
||||
@@ -280,8 +280,8 @@ void UserBufferManagement(unsigned sampsFromUsbToAudio[], unsigned sampsFromAudi
|
||||
#endif
|
||||
};
|
||||
|
||||
buffer_exchange(uc_eq_data, sampsFromUsbToAudio);
|
||||
sampsFromAudioToUsb[0] = sampsFromAudioToUsb[1];
|
||||
buffer_exchange(uc_eq_data, sampsFromUsbToAudio, sampsFromAudioToUsb);
|
||||
// sampsFromAudioToUsb[0] = sampsFromAudioToUsb[1];
|
||||
}
|
||||
|
||||
#ifndef HID_MAX_DATA_BYTES
|
||||
|
||||
@@ -102,7 +102,7 @@ void lfs_deinit(void) {
|
||||
swlock_release(&lfs_lock);
|
||||
}
|
||||
|
||||
#pragma stackfunction 5480
|
||||
#pragma stackfunction 1300
|
||||
void lfs_read_config(unsigned char * config, unsigned char * buffer, unsigned size)
|
||||
{
|
||||
swlock_acquire(&lfs_lock);
|
||||
@@ -130,7 +130,7 @@ void lfs_read_config(unsigned char * config, unsigned char * buffer, unsigned si
|
||||
}
|
||||
|
||||
|
||||
#pragma stackfunction 5480
|
||||
#pragma stackfunction 1300
|
||||
void lfs_write_config(unsigned char * config, unsigned char * buffer, unsigned size)
|
||||
{
|
||||
swlock_acquire(&lfs_lock);
|
||||
|
||||
@@ -1,710 +0,0 @@
|
||||
// Copyright 2020-2021 XMOS LIMITED.
|
||||
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||
|
||||
#define DEBUG_UNIT QSPI_FLASH
|
||||
|
||||
#include "qspi_flash.h"
|
||||
#include "sfdp.h"
|
||||
#if QSPI_FLASH_SANITY_CHECKS
|
||||
/*
|
||||
* Ensure NDEBUG is not defined when the
|
||||
* flash sanity checks are enabled.
|
||||
*/
|
||||
#if defined(NDEBUG)
|
||||
#undef NDEBUG
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include <xcore/assert.h>
|
||||
#include <xcore/hwtimer.h>
|
||||
|
||||
/*
|
||||
* TODO: This isn't fully supported yet
|
||||
*/
|
||||
#define FOUR_BYTE_ADDRESS_SUPPORT 0
|
||||
|
||||
#define BARRIER() asm volatile("": : :"memory")
|
||||
|
||||
#define WRITE_ENABLE_COMMAND QSPI_IO_BYTE_TO_MOSI(0x06)
|
||||
#define WRITE_DISABLE_COMMAND QSPI_IO_BYTE_TO_MOSI(0x04)
|
||||
|
||||
#define ERASE_CHIP_COMMAND QSPI_IO_BYTE_TO_MOSI(0xC7)
|
||||
|
||||
#define PP_1_1_1_COMMAND QSPI_IO_BYTE_TO_MOSI(0x02)
|
||||
#define PP_1_1_4_COMMAND QSPI_IO_BYTE_TO_MOSI(0x32)
|
||||
#define PP_1_4_4_COMMAND QSPI_IO_BYTE_TO_MOSI(0x38)
|
||||
|
||||
#define READ_STATUS_REG_COMMAND QSPI_IO_BYTE_TO_MOSI(0x05)
|
||||
#define READ_ID_COMMAND QSPI_IO_BYTE_TO_MOSI(0x9F)
|
||||
|
||||
#define WRITE_STATUS_REG_COMMAND QSPI_IO_BYTE_TO_MOSI(0x01)
|
||||
|
||||
#define FAST_READ_COMMAND QSPI_IO_BYTE_TO_MOSI(0x0B)
|
||||
#define QUAD_IO_READ_CMD_VAL 0xEB
|
||||
#define QUAD_IO_READ_COMMAND QSPI_IO_BYTE_TO_MOSI(QUAD_IO_READ_CMD_VAL)
|
||||
|
||||
#if FOUR_BYTE_ADDRESS_SUPPORT
|
||||
#define QUAD_IO_READ_DUMMY_CYCLES 6
|
||||
#else
|
||||
#define QUAD_IO_READ_DUMMY_CYCLES 4
|
||||
#endif
|
||||
#define FAST_READ_DUMMY_CYCLES 8
|
||||
|
||||
bool qspi_flash_quad_enable_write(qspi_flash_ctx_t *ctx, bool set)
|
||||
{
|
||||
uint8_t status[2];
|
||||
uint8_t quad_enable_bitmask;
|
||||
const uint32_t no_cmd = QSPI_IO_BYTE_TO_MOSI(0x00);
|
||||
|
||||
if (ctx->qe_reg == 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
xassert(ctx->qe_reg == 1 || ctx->qe_reg == 2);
|
||||
xassert(ctx->qe_bit >= 0 && ctx->qe_bit <= 7);
|
||||
|
||||
quad_enable_bitmask = 1 << ctx->qe_bit;
|
||||
|
||||
if (ctx->qe_reg == 1 || ctx->sr2_read_cmd == no_cmd) {
|
||||
qspi_flash_read_status_register(ctx, status, ctx->qe_reg);
|
||||
} else {
|
||||
qspi_flash_read_status_register(ctx, &status[0], 1);
|
||||
qspi_flash_read_register(ctx, ctx->sr2_read_cmd, &status[1], 1);
|
||||
}
|
||||
|
||||
if (!!(status[ctx->qe_reg - 1] & quad_enable_bitmask) != set) {
|
||||
if (set) {
|
||||
status[ctx->qe_reg - 1] |= quad_enable_bitmask;
|
||||
} else {
|
||||
status[ctx->qe_reg - 1] &= ~quad_enable_bitmask;
|
||||
}
|
||||
|
||||
qspi_flash_write_enable(ctx);
|
||||
|
||||
if (ctx->qe_reg == 1 || ctx->sr2_write_cmd == no_cmd) {
|
||||
qspi_flash_write_status_register(ctx, status, ctx->qe_reg);
|
||||
} else {
|
||||
qspi_flash_write_register(ctx, ctx->sr2_write_cmd, &status[1], 1);
|
||||
}
|
||||
|
||||
qspi_flash_wait_while_write_in_progress(ctx);
|
||||
|
||||
status[0] = 0;
|
||||
status[1] = 0;
|
||||
|
||||
if (ctx->qe_reg == 1 || ctx->sr2_read_cmd == no_cmd) {
|
||||
qspi_flash_read_status_register(ctx, status, ctx->qe_reg);
|
||||
} else {
|
||||
qspi_flash_read_register(ctx, ctx->sr2_read_cmd, &status[1], 1);
|
||||
}
|
||||
|
||||
return !!(status[ctx->qe_reg - 1] & quad_enable_bitmask) == set;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
void qspi_flash_write_enable(qspi_flash_ctx_t *ctx)
|
||||
{
|
||||
qspi_io_ctx_t *qspi_io_ctx = &ctx->qspi_io_ctx;
|
||||
uint8_t status;
|
||||
|
||||
do {
|
||||
qspi_io_start_transaction(qspi_io_ctx, WRITE_ENABLE_COMMAND, 8, qspi_io_full_speed);
|
||||
qspi_io_end_transaction(qspi_io_ctx);
|
||||
qspi_flash_read_status_register(ctx, &status, 1);
|
||||
} while ((status & QSPI_FLASH_STATUS_REG_WEL_BM) == 0);
|
||||
}
|
||||
|
||||
void qspi_flash_write_disable(qspi_flash_ctx_t *ctx)
|
||||
{
|
||||
qspi_io_ctx_t *qspi_io_ctx = &ctx->qspi_io_ctx;
|
||||
uint8_t status;
|
||||
|
||||
do {
|
||||
qspi_io_start_transaction(qspi_io_ctx, WRITE_DISABLE_COMMAND, 8, qspi_io_full_speed);
|
||||
qspi_io_end_transaction(qspi_io_ctx);
|
||||
qspi_flash_read_status_register(ctx, &status, 1);
|
||||
} while ((status & QSPI_FLASH_STATUS_REG_WEL_BM) != 0);
|
||||
}
|
||||
|
||||
bool qspi_flash_write_in_progress(qspi_flash_ctx_t *ctx)
|
||||
{
|
||||
uint8_t status_reg;
|
||||
qspi_flash_read_register(ctx, ctx->busy_poll_cmd, &status_reg, 1);
|
||||
|
||||
return ((status_reg >> ctx->busy_poll_bit) & 1) != ctx->busy_poll_ready_value;
|
||||
}
|
||||
|
||||
void qspi_flash_wait_while_write_in_progress(qspi_flash_ctx_t *ctx)
|
||||
{
|
||||
qspi_flash_poll_register(ctx, ctx->busy_poll_cmd, (1 << ctx->busy_poll_bit), ctx->busy_poll_ready_value << ctx->busy_poll_bit);
|
||||
}
|
||||
|
||||
void qspi_flash_erase(qspi_flash_ctx_t *ctx,
|
||||
uint32_t address,
|
||||
qspi_flash_erase_length_t erase_length)
|
||||
{
|
||||
qspi_io_ctx_t *qspi_io_ctx = &ctx->qspi_io_ctx;
|
||||
|
||||
size_t cycles;
|
||||
uint32_t cmd;
|
||||
uint8_t *address_bytes;
|
||||
|
||||
#if QSPI_FLASH_SANITY_CHECKS
|
||||
uint8_t status_reg;
|
||||
qspi_flash_read_status_register(ctx, &status_reg, 1);
|
||||
xassert(status_reg & QSPI_FLASH_STATUS_REG_WEL_BM);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Manipulate the address so that in memory it is:
|
||||
* {byte 2, byte 1, byte 0, XX}
|
||||
* it will get sent out as 3 bytes.
|
||||
*/
|
||||
address = byterev(address << 8);
|
||||
address_bytes = (uint8_t *) &address;
|
||||
|
||||
xassert(erase_length >= 0 && erase_length <= qspi_flash_erase_chip);
|
||||
if (erase_length > qspi_flash_erase_chip) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (erase_length == qspi_flash_erase_chip) {
|
||||
cmd = ERASE_CHIP_COMMAND;
|
||||
cycles = 8;
|
||||
} else {
|
||||
xassert(ctx->erase_info[erase_length].size_log2 > 0);
|
||||
if (ctx->erase_info[erase_length].size_log2 <= 0) {
|
||||
return;
|
||||
}
|
||||
cmd = ctx->erase_info[erase_length].cmd;
|
||||
cycles = 32;
|
||||
}
|
||||
|
||||
qspi_io_start_transaction(qspi_io_ctx, cmd, cycles, qspi_io_full_speed);
|
||||
if (cycles == 32) {
|
||||
qspi_io_mosi_out(qspi_io_ctx, qspi_io_transfer_normal, address_bytes, 3);
|
||||
}
|
||||
qspi_io_end_transaction(qspi_io_ctx);
|
||||
}
|
||||
|
||||
void qspi_flash_write_register(qspi_flash_ctx_t *ctx,
|
||||
uint32_t cmd,
|
||||
const uint8_t *val,
|
||||
size_t len)
|
||||
{
|
||||
qspi_io_ctx_t *qspi_io_ctx = &ctx->qspi_io_ctx;
|
||||
|
||||
size_t cycles = 8 + /* 8 cycles for the command */
|
||||
8 * len; /* 2 cycles per byte */
|
||||
|
||||
qspi_io_start_transaction(qspi_io_ctx, cmd, cycles, qspi_io_full_speed);
|
||||
qspi_io_mosi_out(qspi_io_ctx, qspi_io_transfer_normal, val, len);
|
||||
qspi_io_end_transaction(qspi_io_ctx);
|
||||
}
|
||||
|
||||
void qspi_flash_write_status_register(qspi_flash_ctx_t *ctx,
|
||||
const uint8_t *val,
|
||||
size_t len)
|
||||
{
|
||||
#if QSPI_FLASH_SANITY_CHECKS
|
||||
uint8_t status_reg;
|
||||
qspi_flash_read_status_register(ctx, &status_reg, 1);
|
||||
xassert(status_reg & QSPI_FLASH_STATUS_REG_WEL_BM);
|
||||
#endif
|
||||
|
||||
qspi_flash_write_register(ctx, WRITE_STATUS_REG_COMMAND, val, len);
|
||||
}
|
||||
|
||||
void qspi_flash_read_register(qspi_flash_ctx_t *ctx,
|
||||
uint32_t cmd,
|
||||
uint8_t *val,
|
||||
size_t len)
|
||||
{
|
||||
qspi_io_ctx_t *qspi_io_ctx = &ctx->qspi_io_ctx;
|
||||
|
||||
size_t cycles = 8 + /* 8 cycles for the command */
|
||||
8 * len; /* 8 cycles per byte */
|
||||
|
||||
qspi_io_start_transaction(qspi_io_ctx, cmd, cycles, qspi_io_spi_read);
|
||||
qspi_io_sio_direction_input(qspi_io_ctx);
|
||||
qspi_io_miso_in(qspi_io_ctx, qspi_io_transfer_normal, val,
|
||||
8 + /* 8 cycles for the command */
|
||||
7, /* input on the last cycle of the first byte */
|
||||
len);
|
||||
// }
|
||||
|
||||
|
||||
qspi_io_end_transaction(qspi_io_ctx);
|
||||
}
|
||||
|
||||
void qspi_flash_read_status_register(qspi_flash_ctx_t *ctx,
|
||||
uint8_t *val,
|
||||
size_t len)
|
||||
{
|
||||
qspi_flash_read_register(ctx, READ_STATUS_REG_COMMAND, val, len);
|
||||
}
|
||||
|
||||
void qspi_flash_read_id(qspi_flash_ctx_t *ctx,
|
||||
uint8_t *val,
|
||||
size_t len)
|
||||
{
|
||||
qspi_flash_read_register(ctx, READ_ID_COMMAND, val, len);
|
||||
}
|
||||
|
||||
void qspi_flash_poll_register(qspi_flash_ctx_t *ctx,
|
||||
uint32_t cmd,
|
||||
const uint8_t mask,
|
||||
const uint8_t val)
|
||||
{
|
||||
qspi_io_ctx_t *qspi_io_ctx = &ctx->qspi_io_ctx;
|
||||
|
||||
size_t cycles = 8 + /* 8 cycles for the command */
|
||||
8 * 2; /* Read the register at least twice */
|
||||
|
||||
qspi_io_start_transaction(qspi_io_ctx, cmd, cycles, qspi_io_spi_read);
|
||||
qspi_io_sio_direction_input(qspi_io_ctx);
|
||||
qspi_io_miso_poll(qspi_io_ctx, mask, val,
|
||||
8 + /* 8 cycles for the command */
|
||||
7); /* input on the last cycle of the first byte */
|
||||
qspi_io_end_transaction(qspi_io_ctx);
|
||||
}
|
||||
|
||||
void qspi_flash_poll_status_register(qspi_flash_ctx_t *ctx,
|
||||
const uint8_t mask,
|
||||
const uint8_t val)
|
||||
{
|
||||
qspi_flash_poll_register(ctx, READ_STATUS_REG_COMMAND, mask, val);
|
||||
}
|
||||
|
||||
__attribute__((always_inline))
|
||||
static void qspi_flash_fast_read_i(qspi_flash_ctx_t *ctx,
|
||||
uint32_t cmd,
|
||||
uint8_t *data,
|
||||
uint32_t address,
|
||||
size_t len)
|
||||
{
|
||||
qspi_io_ctx_t *qspi_io_ctx = &ctx->qspi_io_ctx;
|
||||
uint8_t *address_bytes;
|
||||
|
||||
size_t cycles = 8 + /* 8 cycles for the command */
|
||||
24 + /* 24 cycles for the address */
|
||||
FAST_READ_DUMMY_CYCLES + /* dummy cycles */
|
||||
8 * len; /* 8 cycles per byte */
|
||||
|
||||
size_t input_cycle = 8 + /* 8 cycles for the command */
|
||||
24 + /* 24 cycles for the address */
|
||||
FAST_READ_DUMMY_CYCLES + /* dummy cycles */
|
||||
7; /* input on the last cycle of the first byte */
|
||||
|
||||
|
||||
/*
|
||||
* Manipulate the address so that in memory it is:
|
||||
* {byte 2, byte 1, byte 0, XX}
|
||||
* it will get sent out as 3 bytes.
|
||||
*/
|
||||
address = byterev(address << 8);
|
||||
address_bytes = (uint8_t *) &address;
|
||||
|
||||
qspi_io_start_transaction(qspi_io_ctx, cmd, cycles, qspi_io_full_speed);
|
||||
qspi_io_mosi_out(qspi_io_ctx, qspi_io_transfer_normal, address_bytes, 3);
|
||||
qspi_io_sio_direction_input(qspi_io_ctx);
|
||||
qspi_io_miso_in(qspi_io_ctx, qspi_io_transfer_normal, data, input_cycle, len);
|
||||
qspi_io_end_transaction(qspi_io_ctx);
|
||||
}
|
||||
|
||||
void qspi_flash_fast_read(qspi_flash_ctx_t *ctx,
|
||||
uint8_t *data,
|
||||
uint32_t address,
|
||||
size_t len)
|
||||
{
|
||||
qspi_flash_ctx_t local_ctx = *ctx;
|
||||
qspi_flash_fast_read_i(&local_ctx, QSPI_IO_BYTE_TO_MOSI(FAST_READ_COMMAND), data, address, len);
|
||||
}
|
||||
|
||||
__attribute__ ((noinline))
|
||||
static void qspi_flash_read_calc(const int xip,
|
||||
#if FOUR_BYTE_ADDRESS_SUPPORT
|
||||
const int four_byte_address,
|
||||
#endif
|
||||
uint32_t *address,
|
||||
size_t len,
|
||||
size_t *cycles,
|
||||
size_t *input_cycle)
|
||||
{
|
||||
/* The first input should occur on either the fourth
|
||||
* byte, or the last byte, whichever is first. */
|
||||
const size_t first_input_byte = len > 4 ? 4 : len;
|
||||
|
||||
#if FOUR_BYTE_ADDRESS_SUPPORT
|
||||
if (xip) {
|
||||
*cycles = (four_byte_address ? 8 : 6) + /* 6 or 8 cycles for address */
|
||||
QUAD_IO_READ_DUMMY_CYCLES + /* dummy cycles */
|
||||
2 * len; /* 2 cycles per byte */
|
||||
|
||||
*input_cycle = (four_byte_address ? 8 : 6) + /* 6 or 8 cycles for address */
|
||||
QUAD_IO_READ_DUMMY_CYCLES + /* dummy cycles */
|
||||
2 * first_input_byte - 1; /* input on the last cycle of the first input byte */
|
||||
} else {
|
||||
*cycles = 8 + /* 8 cycles each for command */
|
||||
(four_byte_address ? 8 : 6) + /* 6 or 8 cycles for address */
|
||||
QUAD_IO_READ_DUMMY_CYCLES + /* dummy cycles */
|
||||
2 * len; /* 2 cycles per byte */
|
||||
|
||||
*input_cycle = 8 + /* 8 cycles each for command */
|
||||
(four_byte_address ? 8 : 6) + /* 6 or 8 cycles for address */
|
||||
QUAD_IO_READ_DUMMY_CYCLES + /* dummy cycles */
|
||||
2 * first_input_byte - 1; /* input on the last cycle of the first input byte */
|
||||
}
|
||||
#else
|
||||
if (xip) {
|
||||
*cycles = 8 + /* 8 cycles for address */
|
||||
QUAD_IO_READ_DUMMY_CYCLES + /* dummy cycles */
|
||||
2 * len; /* 2 cycles per byte */
|
||||
|
||||
*input_cycle = 8 + /* 8 cycles for address */
|
||||
QUAD_IO_READ_DUMMY_CYCLES + /* dummy cycles */
|
||||
2 * first_input_byte - 1; /* input on the last cycle of the first input byte */
|
||||
} else {
|
||||
*cycles = 8 * 2 + /* 8 cycles each for command and address */
|
||||
QUAD_IO_READ_DUMMY_CYCLES + /* dummy cycles */
|
||||
2 * len; /* 2 cycles per byte */
|
||||
|
||||
*input_cycle = 8 * 2 + /* 8 cycles each for command and address */
|
||||
QUAD_IO_READ_DUMMY_CYCLES + /* dummy cycles */
|
||||
2 * first_input_byte - 1; /* input on the last cycle of the first input byte */
|
||||
}
|
||||
#endif
|
||||
|
||||
#if FOUR_BYTE_ADDRESS_SUPPORT
|
||||
if (!four_byte_address) {
|
||||
#endif
|
||||
/*
|
||||
* The address is really contained in the upper 24 bits.
|
||||
* The lower 8 bits are essentially 2 dummy cycles.
|
||||
* Rotate, such that the MSB of address is sent out during
|
||||
* the first two dummy cycles. Some flashes use this to
|
||||
* enter "performance" or "XIP" mode.
|
||||
*/
|
||||
*address = (*address << 8) | (*address >> 24);
|
||||
#if FOUR_BYTE_ADDRESS_SUPPORT
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
__attribute__((always_inline))
|
||||
inline void qspi_flash_read_i(qspi_flash_ctx_t *ctx,
|
||||
const qspi_io_transfer_mode_t transfer_mode,
|
||||
const int xip,
|
||||
#if FOUR_BYTE_ADDRESS_SUPPORT
|
||||
const int four_byte_address,
|
||||
#endif
|
||||
uint8_t *data,
|
||||
uint32_t address,
|
||||
size_t len)
|
||||
{
|
||||
qspi_io_ctx_t *qspi_io_ctx = &ctx->qspi_io_ctx;
|
||||
size_t cycles;
|
||||
size_t input_cycle;
|
||||
|
||||
qspi_flash_read_calc(xip,
|
||||
#if FOUR_BYTE_ADDRESS_SUPPORT
|
||||
four_byte_address,
|
||||
#endif
|
||||
&address,
|
||||
len,
|
||||
&cycles,
|
||||
&input_cycle);
|
||||
|
||||
if (xip) {
|
||||
qspi_io_start_transaction(qspi_io_ctx, address, cycles, qspi_io_full_speed);
|
||||
} else {
|
||||
qspi_io_start_transaction(qspi_io_ctx, QUAD_IO_READ_COMMAND, cycles, qspi_io_full_speed);
|
||||
qspi_io_words_out(qspi_io_ctx, qspi_io_transfer_normal, &address, 1);
|
||||
}
|
||||
|
||||
#if FOUR_BYTE_ADDRESS_SUPPORT
|
||||
if (four_byte_address) {
|
||||
uint8_t mode = 0xFF;
|
||||
qspi_io_bytes_out(qspi_io_ctx, transfer_mode, &mode, 1);
|
||||
}
|
||||
#endif
|
||||
|
||||
qspi_io_sio_direction_input(qspi_io_ctx);
|
||||
qspi_io_bytes_in(qspi_io_ctx, transfer_mode, data, input_cycle, len);
|
||||
qspi_io_end_transaction(qspi_io_ctx);
|
||||
}
|
||||
|
||||
void qspi_flash_read(qspi_flash_ctx_t *ctx,
|
||||
uint8_t *data,
|
||||
uint32_t address,
|
||||
size_t len)
|
||||
{
|
||||
qspi_flash_ctx_t local_ctx = *ctx;
|
||||
qspi_flash_read_i(&local_ctx, qspi_io_transfer_normal, 0,
|
||||
#if FOUR_BYTE_ADDRESS_SUPPORT
|
||||
0,
|
||||
#endif
|
||||
data, address, len);
|
||||
}
|
||||
|
||||
void qspi_flash_read_nibble_swapped(qspi_flash_ctx_t *ctx,
|
||||
uint8_t *data,
|
||||
uint32_t address,
|
||||
size_t len)
|
||||
{
|
||||
qspi_flash_ctx_t local_ctx = *ctx;
|
||||
qspi_flash_read_i(&local_ctx, qspi_io_transfer_nibble_swap, 0,
|
||||
#if FOUR_BYTE_ADDRESS_SUPPORT
|
||||
0,
|
||||
#endif
|
||||
data, address, len);
|
||||
}
|
||||
|
||||
void qspi_flash_xip_read(qspi_flash_ctx_t *ctx,
|
||||
uint8_t *data,
|
||||
uint32_t address,
|
||||
size_t len)
|
||||
{
|
||||
qspi_flash_ctx_t local_ctx = *ctx;
|
||||
qspi_flash_read_i(&local_ctx, qspi_io_transfer_normal, 1,
|
||||
#if FOUR_BYTE_ADDRESS_SUPPORT
|
||||
0,
|
||||
#endif
|
||||
data, address, len);
|
||||
}
|
||||
|
||||
void qspi_flash_xip_read_nibble_swapped(qspi_flash_ctx_t *ctx,
|
||||
uint8_t *data,
|
||||
uint32_t address,
|
||||
size_t len)
|
||||
{
|
||||
qspi_flash_ctx_t local_ctx = *ctx;
|
||||
qspi_flash_read_i(&local_ctx, qspi_io_transfer_nibble_swap, 1,
|
||||
#if FOUR_BYTE_ADDRESS_SUPPORT
|
||||
0,
|
||||
#endif
|
||||
data, address, len);
|
||||
}
|
||||
|
||||
__attribute__((always_inline))
|
||||
inline void qspi_flash_write_i(qspi_flash_ctx_t *ctx,
|
||||
const qspi_io_transfer_mode_t transfer_mode,
|
||||
const uint8_t *data,
|
||||
uint32_t address,
|
||||
size_t len)
|
||||
{
|
||||
qspi_io_ctx_t *qspi_io_ctx = &ctx->qspi_io_ctx;
|
||||
|
||||
uint8_t *address_bytes;
|
||||
uint32_t pp_cmd;
|
||||
size_t cycles;
|
||||
|
||||
#if QSPI_FLASH_SANITY_CHECKS
|
||||
uint8_t status_reg;
|
||||
qspi_flash_read_status_register(ctx, &status_reg, 1);
|
||||
xassert(status_reg & QSPI_FLASH_STATUS_REG_WEL_BM);
|
||||
#endif
|
||||
|
||||
switch (ctx->quad_page_program_cmd) {
|
||||
case qspi_flash_page_program_1_1_4:
|
||||
pp_cmd = PP_1_1_4_COMMAND;
|
||||
cycles = 8 + /* 8 cycles for command */
|
||||
24 + /* 24 cycles for address */
|
||||
2 * len; /* 2 cycles per byte */
|
||||
break;
|
||||
case qspi_flash_page_program_1_4_4:
|
||||
pp_cmd = PP_1_4_4_COMMAND;
|
||||
cycles = 8 + /* 8 cycles for command */
|
||||
6 + /* 6 cycles for address */
|
||||
2 * len; /* 2 cycles per byte */
|
||||
break;
|
||||
case qspi_flash_page_program_1_1_1:
|
||||
default:
|
||||
pp_cmd = PP_1_1_1_COMMAND;
|
||||
cycles = 8 + /* 8 cycles for command */
|
||||
24 + /* 24 cycles for address */
|
||||
8 * len; /* 8 cycles per byte */
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Manipulate the address so that in memory it is:
|
||||
* {byte 2, byte 1, byte 0, XX}
|
||||
* it will get sent out as 3 bytes.
|
||||
*/
|
||||
address = byterev(address << 8);
|
||||
address_bytes = (uint8_t *) &address;
|
||||
|
||||
qspi_io_start_transaction(qspi_io_ctx, pp_cmd, cycles, qspi_io_full_speed);
|
||||
switch (ctx->quad_page_program_cmd) {
|
||||
case qspi_flash_page_program_1_1_4:
|
||||
qspi_io_mosi_out(qspi_io_ctx, qspi_io_transfer_normal, address_bytes, 3);
|
||||
qspi_io_bytes_out(qspi_io_ctx, transfer_mode, data, len);
|
||||
break;
|
||||
case qspi_flash_page_program_1_4_4:
|
||||
qspi_io_bytes_out(qspi_io_ctx, qspi_io_transfer_normal, address_bytes, 3);
|
||||
qspi_io_bytes_out(qspi_io_ctx, transfer_mode, data, len);
|
||||
break;
|
||||
case qspi_flash_page_program_1_1_1:
|
||||
default:
|
||||
qspi_io_mosi_out(qspi_io_ctx, qspi_io_transfer_normal, address_bytes, 3);
|
||||
qspi_io_mosi_out(qspi_io_ctx, transfer_mode, data, len);
|
||||
break;
|
||||
}
|
||||
|
||||
qspi_io_end_transaction(qspi_io_ctx);
|
||||
}
|
||||
|
||||
void qspi_flash_write(qspi_flash_ctx_t *ctx,
|
||||
const uint8_t *data,
|
||||
uint32_t address,
|
||||
size_t len)
|
||||
{
|
||||
qspi_flash_ctx_t local_ctx = *ctx;
|
||||
qspi_flash_write_i(&local_ctx, qspi_io_transfer_normal, data, address, len);
|
||||
}
|
||||
|
||||
void qspi_flash_write_nibble_swapped(qspi_flash_ctx_t *ctx,
|
||||
const uint8_t *data,
|
||||
uint32_t address,
|
||||
size_t len)
|
||||
{
|
||||
qspi_flash_ctx_t local_ctx = *ctx;
|
||||
qspi_flash_write_i(&local_ctx, qspi_io_transfer_nibble_swap, data, address, len);
|
||||
}
|
||||
|
||||
SFDP_READ_CALLBACK_ATTR
|
||||
void qspi_flash_sfdp_read(qspi_flash_ctx_t *ctx,
|
||||
uint8_t *data,
|
||||
uint32_t address,
|
||||
size_t len)
|
||||
{
|
||||
qspi_flash_ctx_t local_ctx = *ctx;
|
||||
qspi_flash_fast_read_i(&local_ctx, QSPI_IO_BYTE_TO_MOSI(SFDP_READ_INSTRUCTION), data, address, len);
|
||||
}
|
||||
|
||||
void qspi_flash_deinit(qspi_flash_ctx_t *ctx)
|
||||
{
|
||||
qspi_io_ctx_t *qspi_io_ctx = &ctx->qspi_io_ctx;
|
||||
|
||||
qspi_io_deinit(qspi_io_ctx);
|
||||
}
|
||||
|
||||
void qspi_flash_init(qspi_flash_ctx_t *ctx)
|
||||
{
|
||||
sfdp_info_t sfdp_info;
|
||||
qspi_io_ctx_t *qspi_io_ctx = &ctx->qspi_io_ctx;
|
||||
|
||||
if (!ctx->custom_clock_setup) {
|
||||
ctx->source_clock = qspi_io_source_clock_ref;
|
||||
|
||||
/* 100 / (2 * 2) = 25 MHz */
|
||||
qspi_io_ctx->full_speed_clk_divisor = 2;
|
||||
qspi_io_ctx->full_speed_sclk_sample_delay = 0;
|
||||
qspi_io_ctx->full_speed_sclk_sample_edge = qspi_io_sample_edge_falling;
|
||||
qspi_io_ctx->full_speed_sio_pad_delay = 0;
|
||||
|
||||
/* 100 / (2 * 2) = 25 MHz */
|
||||
qspi_io_ctx->spi_read_clk_divisor = 2;
|
||||
qspi_io_ctx->spi_read_sclk_sample_delay = 0;
|
||||
qspi_io_ctx->spi_read_sclk_sample_edge = qspi_io_sample_edge_falling;
|
||||
qspi_io_ctx->spi_read_sio_pad_delay = 0;
|
||||
}
|
||||
|
||||
/* configure the QSPI I/O interface */
|
||||
qspi_io_init(qspi_io_ctx, ctx->source_clock);
|
||||
|
||||
if ((ctx->sfdp_skip == false) && sfdp_discover(&sfdp_info, ctx, (sfdp_read_cb_t) qspi_flash_sfdp_read)) {
|
||||
int ret;
|
||||
int erase_table_entries;
|
||||
uint8_t read_instruction;
|
||||
uint8_t write_instruction;
|
||||
|
||||
ctx->sfdp_supported = true;
|
||||
|
||||
/* Parameters from SFDP used:
|
||||
* 1) Flash size.
|
||||
* 2) Page size.
|
||||
* 3) Address bytes - 3, 4, or both
|
||||
* Set the "current" address bytes to 3 if it's 3 only.
|
||||
* Otherwise set to 4.
|
||||
* If both modes are allowed, then should switch to 4 byte mode.
|
||||
* 4) Supports_144_fast_read. This is required. Ensure that its command
|
||||
* is 0xEB.
|
||||
* 5) Ensure that the quad i/o read's mode plus dummy clocks equals 6.
|
||||
* 6) All the erase sizes and commands. Sort them and save to a table
|
||||
* inside the flash ctx.
|
||||
* 7) The busy poll method.
|
||||
* 8) The quad enable method.
|
||||
*
|
||||
* TODO:
|
||||
* 9) If XIP mode is supported, The XIP entry/exit methods and implement them.
|
||||
* Should have xip enter/xip exit functions. Reads will need issue the
|
||||
* proper mode bits. Continue to use the xip read function?
|
||||
*/
|
||||
|
||||
/* Verify that the QSPI flash chip supports quad I/O read mode with 6 dummy cycles */
|
||||
xassert(sfdp_info.basic_parameter_table.supports_144_fast_read && "Quad I/O Read mode support is required");
|
||||
xassert(sfdp_info.basic_parameter_table.quad_144_read_cmd == QUAD_IO_READ_CMD_VAL && "Unsupported Quad I/O Read command");
|
||||
xassert(sfdp_info.basic_parameter_table.quad_144_read_mode_clocks + sfdp_info.basic_parameter_table.quad_144_read_dummy_clocks == 6 && "Unsupported number of dummy clocks");
|
||||
|
||||
/* Save the page and flash sizes. Calculate the page count */
|
||||
ctx->page_size_bytes = sfdp_flash_page_size_bytes(&sfdp_info);
|
||||
ctx->flash_size_kbytes = sfdp_flash_size_kbytes(&sfdp_info);
|
||||
if (ctx->flash_size_kbytes) {
|
||||
ctx->page_count = (ctx->flash_size_kbytes >> sfdp_info.basic_parameter_table.page_size) << 10;
|
||||
}
|
||||
xassert(ctx->flash_size_kbytes != 0 && "Unsupported flash size");
|
||||
|
||||
/* Save the supported busy poll method */
|
||||
ret = sfdp_busy_poll_method(&sfdp_info, &read_instruction, &ctx->busy_poll_bit, &ctx->busy_poll_ready_value);
|
||||
if (ret == 0) {
|
||||
ctx->busy_poll_cmd = QSPI_IO_BYTE_TO_MOSI(read_instruction);
|
||||
}
|
||||
xassert(ret == 0 && "Unsupported busy poll method");
|
||||
|
||||
/* Save the supported quad enable method */
|
||||
ret = sfdp_quad_enable_method(&sfdp_info, &ctx->qe_reg, &ctx->qe_bit, &read_instruction, &write_instruction);
|
||||
if (ret == 0) {
|
||||
ctx->sr2_read_cmd = QSPI_IO_BYTE_TO_MOSI(read_instruction);
|
||||
ctx->sr2_write_cmd = QSPI_IO_BYTE_TO_MOSI(write_instruction);
|
||||
}
|
||||
xassert(ret == 0 && "Unsupported QE enable method");
|
||||
|
||||
/* Parse and save the erase table */
|
||||
erase_table_entries = 0;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
if (sfdp_info.basic_parameter_table.erase_info[i].size != 0) {
|
||||
ctx->erase_info[erase_table_entries].size_log2 = sfdp_info.basic_parameter_table.erase_info[i].size;
|
||||
ctx->erase_info[erase_table_entries].cmd = QSPI_IO_BYTE_TO_MOSI(sfdp_info.basic_parameter_table.erase_info[i].cmd);
|
||||
} else {
|
||||
ctx->erase_info[erase_table_entries].size_log2 = 0;
|
||||
}
|
||||
erase_table_entries++;
|
||||
}
|
||||
xassert(erase_table_entries > 0 && "Erase table found in SFDP is empty!");
|
||||
|
||||
/* Determine the number of address bytes. If 4 byte mode is available, switch to it */
|
||||
switch (sfdp_info.basic_parameter_table.address_bytes) {
|
||||
case sfdp_3_or_4_byte_address:
|
||||
ctx->address_bytes = 3; break; /* leave it in 3 byte address mode for now */
|
||||
|
||||
/* TODO: enable 4 byte address mode now and fall thru to next case */
|
||||
// @suppress("No break at end of case")
|
||||
case sfdp_4_byte_address:
|
||||
ctx->address_bytes = 4;
|
||||
xassert(0 && "4 byte address mode entry not yet implemented");
|
||||
break;
|
||||
case sfdp_3_byte_address:
|
||||
default:
|
||||
ctx->address_bytes = 3;
|
||||
break;
|
||||
}
|
||||
|
||||
} else {
|
||||
ctx->sfdp_supported = false;
|
||||
xassert((ctx->address_bytes == 3 || ctx->address_bytes == 4) && ctx->busy_poll_bit <= 7 && (ctx->busy_poll_ready_value == 0 || ctx->busy_poll_ready_value == 1));
|
||||
}
|
||||
}
|
||||
@@ -1,88 +0,0 @@
|
||||
// Copyright 2020-2021 XMOS LIMITED.
|
||||
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "qspi_io.h"
|
||||
|
||||
void qspi_io_deinit(const qspi_io_ctx_t *ctx)
|
||||
{
|
||||
port_disable(ctx->cs_port);
|
||||
port_disable(ctx->sio_port);
|
||||
port_reset(ctx->sclk_port);
|
||||
port_start_buffered(ctx->sclk_port,32);
|
||||
clock_disable(ctx->clock_block);
|
||||
}
|
||||
|
||||
void qspi_io_init(const qspi_io_ctx_t *ctx,
|
||||
qspi_io_source_clock_t source_clock)
|
||||
{
|
||||
/* Setup the clock block */
|
||||
clock_enable(ctx->clock_block);
|
||||
if (source_clock == qspi_io_source_clock_ref) {
|
||||
clock_set_source_clk_ref(ctx->clock_block);
|
||||
} else {
|
||||
clock_set_source_clk_xcore(ctx->clock_block);
|
||||
}
|
||||
|
||||
|
||||
/* Setup the chip select port */
|
||||
port_enable(ctx->cs_port);
|
||||
port_set_clock(ctx->cs_port, ctx->clock_block);
|
||||
/*
|
||||
* CS is used internally as the ready signal for SIO, so it must be
|
||||
* driven high when it is asserted. However, it must be active low
|
||||
* on the chip pin itself for the external QSPI device. Therefore the
|
||||
* CS port is put into invert mode.
|
||||
* NOTE: invert mode is not modeled correctly in xsim VCD trace.
|
||||
*/
|
||||
port_set_invert(ctx->cs_port);
|
||||
/* Set chip select as the ready source for the clock */
|
||||
clock_set_ready_src(ctx->clock_block, ctx->cs_port);
|
||||
|
||||
|
||||
/* Setup the SIO port */
|
||||
port_enable(ctx->sio_port);
|
||||
|
||||
/*
|
||||
* Ensure SIO begins outputing high on all lines.
|
||||
* This requires an active clock.
|
||||
*/
|
||||
port_set_clock(ctx->sio_port, XS1_CLKBLK_REF);
|
||||
port_out(ctx->sio_port, 0xF);
|
||||
port_sync(ctx->sio_port);
|
||||
|
||||
/* Now set SIO to use the desired clock block. */
|
||||
port_set_clock(ctx->sio_port, ctx->clock_block);
|
||||
|
||||
/*
|
||||
* Always sample on the falling edge. This allows for
|
||||
* faster SCLK frequencies, but in general works with
|
||||
* any frequency that meets timing. This also ensures
|
||||
* that the internal CS ready signal is captured on time
|
||||
* at higher frequencies, so is important both when SIO
|
||||
* is input and output.
|
||||
*/
|
||||
port_set_sample_falling_edge(ctx->sio_port);
|
||||
|
||||
/*
|
||||
* SIO is put into strobed slave mode. CS is already
|
||||
* setup as the ready signal for SCLK. This ensures that
|
||||
* the data does not begin shifting out out until CS
|
||||
* is asserted.
|
||||
*/
|
||||
port_set_buffered(ctx->sio_port);
|
||||
port_set_transfer_width(ctx->sio_port, 32);
|
||||
port_set_ready_strobed(ctx->sio_port);
|
||||
port_set_slave(ctx->sio_port);
|
||||
|
||||
/* Ensure the buffer is clear before the first transaction. */
|
||||
port_clear_buffer(ctx->sio_port);
|
||||
|
||||
|
||||
/* Setup the SCLK port */
|
||||
port_enable(ctx->sclk_port);
|
||||
port_set_clock(ctx->sclk_port, ctx->clock_block);
|
||||
port_set_out_clock(ctx->sclk_port);
|
||||
}
|
||||
|
||||
@@ -1,168 +0,0 @@
|
||||
// Copyright 2021 XMOS LIMITED.
|
||||
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||
|
||||
#define DEBUG_UNIT SFDP
|
||||
|
||||
#include "sfdp.h"
|
||||
|
||||
size_t sfdp_flash_size_kbytes(sfdp_info_t *sfdp_info)
|
||||
{
|
||||
size_t flash_size_kbytes;
|
||||
if (sfdp_info->basic_parameter_table.memory_density_is_exponent) {
|
||||
if (sfdp_info->basic_parameter_table.memory_density >=32 && sfdp_info->basic_parameter_table.memory_density <= 44) {
|
||||
flash_size_kbytes = 1 << (sfdp_info->basic_parameter_table.memory_density - 13);
|
||||
} else {
|
||||
flash_size_kbytes = 0;
|
||||
}
|
||||
} else {
|
||||
flash_size_kbytes = (1 + sfdp_info->basic_parameter_table.memory_density) >> 13;
|
||||
}
|
||||
|
||||
return flash_size_kbytes;
|
||||
}
|
||||
|
||||
size_t sfdp_flash_page_size_bytes(sfdp_info_t *sfdp_info)
|
||||
{
|
||||
return 1 << sfdp_info->basic_parameter_table.page_size;
|
||||
}
|
||||
|
||||
int sfdp_busy_poll_method(sfdp_info_t *sfdp_info,
|
||||
uint8_t *instruction,
|
||||
uint8_t *bit,
|
||||
uint8_t *ready_value)
|
||||
{
|
||||
uint32_t method_set = sfdp_info->basic_parameter_table.busy_poll_methods;
|
||||
if (method_set & SFDP_BUSY_POLL_ALT1_BM) {
|
||||
*instruction = 0x70;
|
||||
*bit = 7;
|
||||
*ready_value = 1;
|
||||
} else if (method_set & SFDP_BUSY_POLL_LEGACY_BM) {
|
||||
*instruction = 0x05;
|
||||
*bit = 0;
|
||||
*ready_value = 0;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sfdp_quad_enable_method(sfdp_info_t *sfdp_info,
|
||||
uint8_t *qe_reg,
|
||||
uint8_t *qe_bit,
|
||||
uint8_t *sr2_read_instruction,
|
||||
uint8_t *sr2_write_instruction)
|
||||
{
|
||||
switch (sfdp_info->basic_parameter_table.quad_enable_method) {
|
||||
case 0:
|
||||
*qe_reg = 0;
|
||||
*qe_bit = 0;
|
||||
*sr2_read_instruction = 0;
|
||||
*sr2_write_instruction = 0;
|
||||
break;
|
||||
case 1:
|
||||
*qe_reg = 2;
|
||||
*qe_bit = 1;
|
||||
*sr2_read_instruction = 0;
|
||||
*sr2_write_instruction = 0;
|
||||
break;
|
||||
case 2:
|
||||
*qe_reg = 1;
|
||||
*qe_bit = 6;
|
||||
*sr2_read_instruction = 0;
|
||||
*sr2_write_instruction = 0;
|
||||
break;
|
||||
case 3:
|
||||
*qe_reg = 2;
|
||||
*qe_bit = 7;
|
||||
*sr2_read_instruction = 0x3F;
|
||||
*sr2_write_instruction = 0x3E;
|
||||
break;
|
||||
case 4:
|
||||
*qe_reg = 2;
|
||||
*qe_bit = 1;
|
||||
*sr2_read_instruction = 0;
|
||||
*sr2_write_instruction = 0;
|
||||
break;
|
||||
case 5:
|
||||
*qe_reg = 2;
|
||||
*qe_bit = 1;
|
||||
*sr2_read_instruction = 0x35;
|
||||
*sr2_write_instruction = 0;
|
||||
break;
|
||||
case 6:
|
||||
*qe_reg = 2;
|
||||
*qe_bit = 1;
|
||||
*sr2_read_instruction = 0x35;
|
||||
*sr2_write_instruction = 0x31;
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void sfdp_erase_table_sort(sfdp_info_t *sfdp_info)
|
||||
{
|
||||
sfdp_parameter_table_t *t = &sfdp_info->basic_parameter_table;
|
||||
const int n = 4;
|
||||
int i, j;
|
||||
for (i = 0; i < n - 1; i++) {
|
||||
for (j = 0; j < n - i - 1; j++) {
|
||||
/* Treat size 0 as a maximum value to keep them at the end of the table */
|
||||
if (t->erase_info[j].size == 0 || (t->erase_info[j + 1].size != 0 && t->erase_info[j].size > t->erase_info[j + 1].size)) {
|
||||
uint8_t size = t->erase_info[j].size;
|
||||
uint8_t cmd = t->erase_info[j].cmd;
|
||||
t->erase_info[j].size = t->erase_info[j + 1].size;
|
||||
t->erase_info[j].cmd = t->erase_info[j + 1].cmd;
|
||||
t->erase_info[j + 1].size = size;
|
||||
t->erase_info[j + 1].cmd = cmd;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool sfdp_discover(sfdp_info_t *sfdp_info,
|
||||
void *serial_flash_ctx,
|
||||
SFDP_READ_CALLBACK_ATTR sfdp_read_cb_t sfdp_read)
|
||||
{
|
||||
const uint32_t sfdp_signature = 0x50444653;
|
||||
const uint8_t req_major_revision = 1;
|
||||
const uint8_t req_min_minor_revision = 5;
|
||||
size_t table_read_length;
|
||||
|
||||
sfdp_read(serial_flash_ctx, sfdp_info, 0x000000, sizeof(sfdp_header_t) + sizeof(sfdp_parameter_header_t));
|
||||
|
||||
table_read_length = sizeof(uint32_t) * sfdp_info->basic_parameter_header.length;
|
||||
|
||||
if (sfdp_info->sfdp_header.signature == sfdp_signature &&
|
||||
sfdp_info->sfdp_header.major_revision == req_major_revision &&
|
||||
sfdp_info->basic_parameter_header.major_revision == req_major_revision &&
|
||||
sfdp_info->sfdp_header.minor_revision >= req_min_minor_revision &&
|
||||
sfdp_info->basic_parameter_header.minor_revision >= req_min_minor_revision &&
|
||||
table_read_length >= sizeof(sfdp_parameter_table_t)) {
|
||||
|
||||
// debug_printf("Supported SFDP flash device found\n");
|
||||
|
||||
} else {
|
||||
if (sfdp_info->sfdp_header.signature != sfdp_signature) {
|
||||
// debug_printf("No SFDP flash device found\n");
|
||||
} else {
|
||||
// debug_printf("Unsupported SFDP flash device found\n");
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (sizeof(sfdp_parameter_table_t) < table_read_length) {
|
||||
table_read_length = sizeof(sfdp_parameter_table_t);
|
||||
}
|
||||
|
||||
sfdp_read(serial_flash_ctx, &sfdp_info->basic_parameter_table, sfdp_info->basic_parameter_header.table_address, table_read_length);
|
||||
|
||||
/* Ensure that the erase table is sorted by size, with unused entries at the end. */
|
||||
sfdp_erase_table_sort(sfdp_info);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -21,19 +21,13 @@ extern void SetEqDataChan (chanend c);
|
||||
/* I2C interface ports */
|
||||
extern port p_scl;
|
||||
extern port p_sda;
|
||||
extern void i2c_control_task(void);
|
||||
|
||||
extern int dsp_worker_tile(chanend c_dsp_to_ex3d, int worker_id);
|
||||
//extern int dsp_worker_tile_1(chanend c_dsp_to_ex3d, int worker_id);
|
||||
extern void ex3d_task();
|
||||
extern void hid_button_task(chanend cc_mic_level, chanend c_hid, chanend c_hidSendData, chanend c_uac_vol);
|
||||
extern void AudioHwRemote(chanend c_hidSendData, chanend cc_mic_level, chanend c_uac_vol);
|
||||
#if AIZIP_DNR == 1
|
||||
extern void dnr_dsp_buffer_task(chanend cc_dsp_in, chanend cc_dsp_eof, chanend cc_mic_level);
|
||||
extern void dnr_dsp_proc_task(chanend cc_dsp_eof);
|
||||
#else
|
||||
//#define dnr_dsp_buffer_task(cc_dsp_in, cc_dsp_eof, cc_mic_level)
|
||||
//#define dnr_dsp_proc_task(cc_dsp_eof)
|
||||
#endif
|
||||
extern void dnr_dsp_proc_task(void);
|
||||
|
||||
//XUA_DFU_EN do i need it?
|
||||
|
||||
@@ -130,6 +124,8 @@ extern void key_receiver(chanend c_key);
|
||||
{ dsp_core0(); } \
|
||||
}\
|
||||
on tile[0]: {dsp_main(c_eq_data); } \
|
||||
on tile[0]: {dnr_dsp_proc_task(); } \
|
||||
|
||||
|
||||
#endif // AIZIP_DNR
|
||||
|
||||
|
||||
Reference in New Issue
Block a user