Browse Source

Fixed sample rate not set correctly under slave I2S mode. (Tested this time. ^_^)
Added locking mechanism to periperials on SPI1.
Added DMA mode read/write routine to SPI Flash. (Debug reuiqred. WARNING: !!! ENABLING DMA MODE MAY DESTROY YOUR DATA IN THE SPI FLASH !!!)

git-svn-id: https://rt-thread.googlecode.com/svn/trunk@538 bbd45198-f89e-11dd-88c7-29a3b14d5316

kyle.hu.gz 15 years ago
parent
commit
04428f9a8a
5 changed files with 623 additions and 442 deletions
  1. 8 1
      bsp/stm32_radio/board.c
  2. 2 0
      bsp/stm32_radio/board.h
  3. 398 383
      bsp/stm32_radio/codec.c
  4. 213 57
      bsp/stm32_radio/spi_flash.c
  5. 2 1
      bsp/stm32_radio/spi_flash.h

+ 8 - 1
bsp/stm32_radio/board.c

@@ -18,6 +18,8 @@
 #include "stm32f10x.h"
 #include "stm32f10x.h"
 #include "board.h"
 #include "board.h"
 
 
+struct rt_semaphore spi1_lock;
+
 /**
 /**
  * @addtogroup STM32
  * @addtogroup STM32
  */
  */
@@ -87,7 +89,7 @@ static void all_device_reset(void)
                            | RCC_APB2Periph_GPIOF | RCC_APB2Periph_GPIOG,ENABLE);
                            | RCC_APB2Periph_GPIOF | RCC_APB2Periph_GPIOG,ENABLE);
 
 
     GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_Out_PP;
     GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_Out_PP;
-    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
+    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
 
 
     /* SDIO POWER */
     /* SDIO POWER */
     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
@@ -279,6 +281,11 @@ void rt_hw_board_init()
         /* Enable SPI_MASTER */
         /* Enable SPI_MASTER */
         SPI_Cmd(SPI1, ENABLE);
         SPI_Cmd(SPI1, ENABLE);
         SPI_CalculateCRC(SPI1, DISABLE);
         SPI_CalculateCRC(SPI1, DISABLE);
+
+    	if (rt_sem_init(&spi1_lock, "spi1lock", 1, RT_IPC_FLAG_FIFO) != RT_EOK)
+    	{
+    		rt_kprintf("init spi1 lock semaphore failed\n");
+    	}
     }
     }
 
 
 }/* rt_hw_board_init */
 }/* rt_hw_board_init */

+ 2 - 0
bsp/stm32_radio/board.h

@@ -69,6 +69,8 @@ void rt_hw_board_init(void);
 void rt_hw_usart_init(void);
 void rt_hw_usart_init(void);
 void rt_hw_sdcard_init(void);
 void rt_hw_sdcard_init(void);
 
 
+extern struct rt_semaphore spi1_lock;
+
 #endif
 #endif
 
 
 // <<< Use Configuration Wizard in Context Menu >>>
 // <<< Use Configuration Wizard in Context Menu >>>

+ 398 - 383
bsp/stm32_radio/codec.c

@@ -81,6 +81,10 @@ struct codec_device codec;
 
 
 static uint16_t r06 = REG_CLOCK_GEN | CLKSEL_PLL | MCLK_DIV2 | BCLK_DIV8;
 static uint16_t r06 = REG_CLOCK_GEN | CLKSEL_PLL | MCLK_DIV2 | BCLK_DIV8;
 
 
+#if !CODEC_MASTER_MODE
+static int codec_sr_new = 0;
+#endif
+
 static void NVIC_Configuration(void)
 static void NVIC_Configuration(void)
 {
 {
     NVIC_InitTypeDef NVIC_InitStructure;
     NVIC_InitTypeDef NVIC_InitStructure;
@@ -97,49 +101,49 @@ static void GPIO_Configuration(void)
 {
 {
     GPIO_InitTypeDef GPIO_InitStructure;
     GPIO_InitTypeDef GPIO_InitStructure;
 
 
-    /* Disable the JTAG interface and enable the SWJ interface */
-    GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE);
+	/* Disable the JTAG interface and enable the SWJ interface */
+	GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE);
 
 
-    /* PC5 CODEC CS */
-    GPIO_InitStructure.GPIO_Pin = CODEC_CSB_PIN;
-    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
-    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
-    GPIO_Init(CODEC_CSB_PORT, &GPIO_InitStructure);
+	/* PC5 CODEC CS */
+	GPIO_InitStructure.GPIO_Pin = CODEC_CSB_PIN;
+	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
+	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
+	GPIO_Init(CODEC_CSB_PORT, &GPIO_InitStructure);
 
 
-    // WS
-    GPIO_InitStructure.GPIO_Pin = CODEC_I2S_WS_PIN;
-    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;
+	// WS
+	GPIO_InitStructure.GPIO_Pin = CODEC_I2S_WS_PIN;
+	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
 #if CODEC_MASTER_MODE
 #if CODEC_MASTER_MODE
-    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD;
+	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD;
 #else
 #else
-    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
+	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
 #endif
 #endif
-    GPIO_Init(CODEC_I2S_WS_PORT, &GPIO_InitStructure);
+	GPIO_Init(CODEC_I2S_WS_PORT, &GPIO_InitStructure);
 
 
-    // CK
-    GPIO_InitStructure.GPIO_Pin = CODEC_I2S_CK_PIN;
-    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;
+	// CK
+	GPIO_InitStructure.GPIO_Pin = CODEC_I2S_CK_PIN;
+	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;
 #if CODEC_MASTER_MODE
 #if CODEC_MASTER_MODE
-    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
+	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
 #else
 #else
-    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
+	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
 #endif
 #endif
-    GPIO_Init(CODEC_I2S_CK_PORT, &GPIO_InitStructure);
+	GPIO_Init(CODEC_I2S_CK_PORT, &GPIO_InitStructure);
 
 
-    // SD
-    GPIO_InitStructure.GPIO_Pin = CODEC_I2S_SD_PIN;
-    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;
-    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
-    GPIO_Init(CODEC_I2S_SD_PORT, &GPIO_InitStructure);
+	// SD
+	GPIO_InitStructure.GPIO_Pin = CODEC_I2S_SD_PIN;
+	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;
+	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
+	GPIO_Init(CODEC_I2S_SD_PORT, &GPIO_InitStructure);
 
 
 #ifdef CODEC_USE_MCO
 #ifdef CODEC_USE_MCO
-    /*    MCO    configure */
-    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
-    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
-    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
-    GPIO_Init(GPIOA,&GPIO_InitStructure);
+	/*    MCO    configure */
+	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
+	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
+	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
+	GPIO_Init(GPIOA,&GPIO_InitStructure);
 
 
-    RCC_MCOConfig(RCC_MCO_HSE);
+	RCC_MCOConfig(RCC_MCO_HSE);
 #endif
 #endif
 }
 }
 
 
@@ -147,132 +151,136 @@ static void DMA_Configuration(rt_uint32_t addr, rt_size_t size)
 {
 {
     DMA_InitTypeDef DMA_InitStructure;
     DMA_InitTypeDef DMA_InitStructure;
 
 
-    /* DMA Channel configuration ----------------------------------------------*/
-    DMA_Cmd(CODEC_I2S_DMA, DISABLE);
-    DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)(&(CODEC_I2S_PORT->DR));
-    DMA_InitStructure.DMA_MemoryBaseAddr = (u32) addr;
-    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
-    DMA_InitStructure.DMA_BufferSize = size;
-    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
-    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
-    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
-    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
-    DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;
-    DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
-    DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
-    DMA_Init(CODEC_I2S_DMA, &DMA_InitStructure);
-
-    /* Enable SPI DMA Tx request */
-    SPI_I2S_DMACmd(CODEC_I2S_PORT, SPI_I2S_DMAReq_Tx, ENABLE);
-
-    DMA_ITConfig(CODEC_I2S_DMA, DMA_IT_TC, ENABLE);
-    DMA_Cmd(CODEC_I2S_DMA, ENABLE);
+	/* DMA Channel configuration ----------------------------------------------*/
+	DMA_Cmd(CODEC_I2S_DMA, DISABLE);
+	DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)(&(CODEC_I2S_PORT->DR));
+	DMA_InitStructure.DMA_MemoryBaseAddr = (u32) addr;
+	DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
+	DMA_InitStructure.DMA_BufferSize = size;
+	DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
+	DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
+	DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
+	DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
+	DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;
+	DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
+	DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
+	DMA_Init(CODEC_I2S_DMA, &DMA_InitStructure);
+
+	/* Enable SPI DMA Tx request */
+	SPI_I2S_DMACmd(CODEC_I2S_PORT, SPI_I2S_DMAReq_Tx, ENABLE);
+
+	DMA_ITConfig(CODEC_I2S_DMA, DMA_IT_TC, ENABLE);
+	DMA_Cmd(CODEC_I2S_DMA, ENABLE);
 }
 }
 
 
 static void I2S_Configuration(uint32_t I2S_AudioFreq)
 static void I2S_Configuration(uint32_t I2S_AudioFreq)
 {
 {
-    I2S_InitTypeDef I2S_InitStructure;
+	I2S_InitTypeDef I2S_InitStructure;
 
 
-    /* I2S peripheral configuration */
-    I2S_InitStructure.I2S_Standard = I2S_Standard_Phillips;
-    I2S_InitStructure.I2S_DataFormat = I2S_DataFormat_16b;
-    I2S_InitStructure.I2S_MCLKOutput = I2S_MCLKOutput_Disable;
-    I2S_InitStructure.I2S_AudioFreq = I2S_AudioFreq;
-    I2S_InitStructure.I2S_CPOL = I2S_CPOL_Low;
+	/* I2S peripheral configuration */
+	I2S_InitStructure.I2S_Standard = I2S_Standard_Phillips;
+	I2S_InitStructure.I2S_DataFormat = I2S_DataFormat_16b;
+	I2S_InitStructure.I2S_MCLKOutput = I2S_MCLKOutput_Disable;
+	I2S_InitStructure.I2S_AudioFreq = I2S_AudioFreq;
+	I2S_InitStructure.I2S_CPOL = I2S_CPOL_Low;
 
 
-    /* I2S2 configuration */
+	/* I2S2 configuration */
 #if CODEC_MASTER_MODE
 #if CODEC_MASTER_MODE
-    I2S_InitStructure.I2S_Mode = I2S_Mode_SlaveTx;
+	I2S_InitStructure.I2S_Mode = I2S_Mode_SlaveTx;
 #else
 #else
-    I2S_InitStructure.I2S_Mode = I2S_Mode_MasterTx;
+	I2S_InitStructure.I2S_Mode = I2S_Mode_MasterTx;
 #endif
 #endif
-    I2S_Init(CODEC_I2S_PORT, &I2S_InitStructure);
+	I2S_Init(CODEC_I2S_PORT, &I2S_InitStructure);
 }
 }
 
 
 uint8_t SPI_WriteByte(unsigned char data)
 uint8_t SPI_WriteByte(unsigned char data)
 {
 {
-    //Wait until the transmit buffer is empty
-    while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET);
-    // Send the byte
-    SPI_I2S_SendData(SPI1, data);
-
-    //Wait until a data is received
-    while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET);
-    // Get the received data
-    data = SPI_I2S_ReceiveData(SPI1);
-
-    // Return the shifted data
-    return data;
+	//Wait until the transmit buffer is empty
+	while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET);
+	// Send the byte
+	SPI_I2S_SendData(SPI1, data);
+
+	//Wait until a data is received
+	while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET);
+	// Get the received data
+	data = SPI_I2S_ReceiveData(SPI1);
+
+	// Return the shifted data
+	return data;
 }
 }
 
 
 static void codec_send(rt_uint16_t s_data)
 static void codec_send(rt_uint16_t s_data)
 {
 {
-    codec_reset_csb();
-    SPI_WriteByte((s_data >> 8) & 0xFF);
-    SPI_WriteByte(s_data & 0xFF);
-    codec_set_csb();
+	rt_sem_take(&spi1_lock, RT_WAITING_FOREVER);
+
+	codec_reset_csb();
+	SPI_WriteByte((s_data >> 8) & 0xFF);
+	SPI_WriteByte(s_data & 0xFF);
+	codec_set_csb();
+
+	rt_sem_release(&spi1_lock);
 }
 }
 
 
 static rt_err_t codec_init(rt_device_t dev)
 static rt_err_t codec_init(rt_device_t dev)
 {
 {
-    codec_send(REG_SOFTWARE_RESET);
-
-    // 1.5x boost power up sequence.
-    // Mute all outputs.
-    codec_send(REG_LOUT1_VOL | LOUT1MUTE);
-    codec_send(REG_ROUT1_VOL | ROUT1MUTE);
-    codec_send(REG_LOUT2_VOL | LOUT2MUTE);
-    codec_send(REG_ROUT2_VOL | ROUT2MUTE);
-    // Enable unused output chosen from L/ROUT2, OUT3 or OUT4.
-    codec_send(REG_POWER_MANAGEMENT3 | OUT4EN);
-    // Set BUFDCOPEN=1 and BUFIOEN=1 in register R1
-    codec_send(REG_POWER_MANAGEMENT1 | BUFDCOPEN | BUFIOEN);
-    // Set SPKBOOST=1 in register R49.
-    codec_send(REG_OUTPUT | SPKBOOST);
-    // Set VMIDSEL[1:0] to required value in register R1.
-    codec_send(REG_POWER_MANAGEMENT1 | BUFDCOPEN | BUFIOEN | VMIDSEL_75K);
-    // Set L/RMIXEN=1 and DACENL/R=1 in register R3.
-    codec_send(REG_POWER_MANAGEMENT3 | LMIXEN | RMIXEN | DACENL | DACENR);
-    // Set BIASEN=1 in register R1.
-    codec_send(REG_POWER_MANAGEMENT1 | BUFDCOPEN | BUFIOEN | VMIDSEL_75K | BIASEN);
-    // Set L/ROUT2EN=1 in register R3.
-    codec_send(REG_POWER_MANAGEMENT3 | LMIXEN | RMIXEN | DACENL | DACENR | LOUT2EN | ROUT2EN);
-    // Enable other mixers as required.
-    // Enable other outputs as required.
-    codec_send(REG_POWER_MANAGEMENT2 | LOUT1EN | ROUT1EN | BOOSTENL | BOOSTENR | INPPGAENL | INPPGAENR);
-
-    // Digital inferface setup.
-    codec_send(REG_AUDIO_INTERFACE | BCP_NORMAL | LRP_NORMAL | WL_16BITS | FMT_I2S);
-
-    // PLL setup.
-    // fs = 44.1KHz * 256fs = 11.2896MHz
-    // F_PLL = 11.2896MHz * 4 * 2 = 90.3168MHz
-    // R = 90.3168MHz / 12.288MHz = 7.35
-    // PLL_N = 7
-    // PLL_K = 0x59999A (0x5A5A5A for STM32's 44.117KHz fs generated from 72MHz clock)
-    codec_send(REG_PLL_N | 7);
+	codec_send(REG_SOFTWARE_RESET);
+
+	// 1.5x boost power up sequence.
+	// Mute all outputs.
+	codec_send(REG_LOUT1_VOL | LOUT1MUTE);
+	codec_send(REG_ROUT1_VOL | ROUT1MUTE);
+	codec_send(REG_LOUT2_VOL | LOUT2MUTE);
+	codec_send(REG_ROUT2_VOL | ROUT2MUTE);
+	// Enable unused output chosen from L/ROUT2, OUT3 or OUT4.
+	codec_send(REG_POWER_MANAGEMENT3 | OUT4EN);
+	// Set BUFDCOPEN=1 and BUFIOEN=1 in register R1
+	codec_send(REG_POWER_MANAGEMENT1 | BUFDCOPEN | BUFIOEN);
+	// Set SPKBOOST=1 in register R49.
+	codec_send(REG_OUTPUT | SPKBOOST);
+	// Set VMIDSEL[1:0] to required value in register R1.
+	codec_send(REG_POWER_MANAGEMENT1 | BUFDCOPEN | BUFIOEN | VMIDSEL_75K);
+	// Set L/RMIXEN=1 and DACENL/R=1 in register R3.
+	codec_send(REG_POWER_MANAGEMENT3 | LMIXEN | RMIXEN | DACENL | DACENR);
+	// Set BIASEN=1 in register R1.
+	codec_send(REG_POWER_MANAGEMENT1 | BUFDCOPEN | BUFIOEN | VMIDSEL_75K | BIASEN);
+	// Set L/ROUT2EN=1 in register R3.
+	codec_send(REG_POWER_MANAGEMENT3 | LMIXEN | RMIXEN | DACENL | DACENR | LOUT2EN | ROUT2EN);
+	// Enable other mixers as required.
+	// Enable other outputs as required.
+	codec_send(REG_POWER_MANAGEMENT2 | LOUT1EN | ROUT1EN | BOOSTENL | BOOSTENR | INPPGAENL | INPPGAENR);
+
+	// Digital inferface setup.
+	codec_send(REG_AUDIO_INTERFACE | BCP_NORMAL | LRP_NORMAL | WL_16BITS | FMT_I2S);
+
+	// PLL setup.
+	// fs = 44.1KHz * 256fs = 11.2896MHz
+	// F_PLL = 11.2896MHz * 4 * 2 = 90.3168MHz
+	// R = 90.3168MHz / 12.288MHz = 7.35
+	// PLL_N = 7
+	// PLL_K = 0x59999A (0x5A5A5A for STM32's 44.117KHz fs generated from 72MHz clock)
+	codec_send(REG_PLL_N | 7);
 #if CODEC_MASTER_MODE
 #if CODEC_MASTER_MODE
-    codec_send(REG_PLL_K1 | 0x16);
-    codec_send(REG_PLL_K2 | 0xCC);
-    codec_send(REG_PLL_K3 | 0x19A);
+	codec_send(REG_PLL_K1 | 0x16);
+	codec_send(REG_PLL_K2 | 0xCC);
+	codec_send(REG_PLL_K3 | 0x19A);
 #else
 #else
-    codec_send(REG_PLL_K1 | 0x16);
-    codec_send(REG_PLL_K2 | 0x12D);
-    codec_send(REG_PLL_K3 | 0x5A);
+	codec_send(REG_PLL_K1 | 0x16);
+	codec_send(REG_PLL_K2 | 0x12D);
+	codec_send(REG_PLL_K3 | 0x5A);
 #endif
 #endif
-    codec_send(REG_POWER_MANAGEMENT1 | BUFDCOPEN | BUFIOEN | VMIDSEL_75K | BIASEN | PLLEN);
-    codec_send(r06);
+	codec_send(REG_POWER_MANAGEMENT1 | BUFDCOPEN | BUFIOEN | VMIDSEL_75K | BIASEN | PLLEN);
+	codec_send(r06);
 
 
-    // Enable DAC 128x oversampling.
-    codec_send(REG_DAC | DACOSR128);
+	// Enable DAC 128x oversampling.
+	codec_send(REG_DAC | DACOSR128);
 
 
-    // Set LOUT2/ROUT2 in BTL operation.
-    codec_send(REG_BEEP | INVROUT2);
+	// Set LOUT2/ROUT2 in BTL operation.
+	codec_send(REG_BEEP | INVROUT2);
 
 
-    // Set output volume.
-    vol(25);
+	// Set output volume.
+	vol(25);
 
 
-    return RT_EOK;
+	return RT_EOK;
 }
 }
 
 
 // Exported functions
 // Exported functions
@@ -280,136 +288,136 @@ static rt_err_t codec_init(rt_device_t dev)
 
 
 void vol(uint16_t v)
 void vol(uint16_t v)
 {
 {
-    v = (v & VOL_MASK) << VOL_POS;
-    codec_send(REG_LOUT1_VOL | v);
-    codec_send(REG_ROUT1_VOL | HPVU | v);
-    codec_send(REG_LOUT2_VOL | v);
-    codec_send(REG_ROUT2_VOL | SPKVU | v);
+	v = (v & VOL_MASK) << VOL_POS;
+	codec_send(REG_LOUT1_VOL | v);
+	codec_send(REG_ROUT1_VOL | HPVU | v);
+	codec_send(REG_LOUT2_VOL | v);
+	codec_send(REG_ROUT2_VOL | SPKVU | v);
 }
 }
 
 
 void eq(codec_eq_args_t args)
 void eq(codec_eq_args_t args)
 {
 {
-    switch (args->channel)
-    {
-    case 1:
-        codec_send(REG_EQ1 | ((args->frequency & EQC_MASK) << EQC_POS) | ((args->gain & EQG_MASK) << EQG_POS) | (args->mode_bandwidth ? EQ3DMODE_DAC : EQ3DMODE_ADC));
-        break;
-
-    case 2:
-        codec_send(REG_EQ2 | ((args->frequency & EQC_MASK) << EQC_POS) | ((args->gain & EQG_MASK) << EQG_POS) | (args->mode_bandwidth ? EQ2BW_WIDE : EQ2BW_NARROW));
-        break;
-
-    case 3:
-        codec_send(REG_EQ3 | ((args->frequency & EQC_MASK) << EQC_POS) | ((args->gain & EQG_MASK) << EQG_POS) | (args->mode_bandwidth ? EQ3BW_WIDE : EQ3BW_NARROW));
-        break;
-
-    case 4:
-        codec_send(REG_EQ4 | ((args->frequency & EQC_MASK) << EQC_POS) | ((args->gain & EQG_MASK) << EQG_POS) | (args->mode_bandwidth ? EQ4BW_WIDE : EQ4BW_NARROW));
-        break;
-
-    case 5:
-        codec_send(REG_EQ5 | ((args->frequency & EQC_MASK) << EQC_POS) | ((args->gain & EQG_MASK) << EQG_POS));
-        break;
-    }
+	switch (args->channel)
+	{
+	case 1:
+		codec_send(REG_EQ1 | ((args->frequency & EQC_MASK) << EQC_POS) | ((args->gain & EQG_MASK) << EQG_POS) | (args->mode_bandwidth ? EQ3DMODE_DAC : EQ3DMODE_ADC));
+		break;
+
+	case 2:
+		codec_send(REG_EQ2 | ((args->frequency & EQC_MASK) << EQC_POS) | ((args->gain & EQG_MASK) << EQG_POS) | (args->mode_bandwidth ? EQ2BW_WIDE : EQ2BW_NARROW));
+		break;
+
+	case 3:
+		codec_send(REG_EQ3 | ((args->frequency & EQC_MASK) << EQC_POS) | ((args->gain & EQG_MASK) << EQG_POS) | (args->mode_bandwidth ? EQ3BW_WIDE : EQ3BW_NARROW));
+		break;
+
+	case 4:
+		codec_send(REG_EQ4 | ((args->frequency & EQC_MASK) << EQC_POS) | ((args->gain & EQG_MASK) << EQG_POS) | (args->mode_bandwidth ? EQ4BW_WIDE : EQ4BW_NARROW));
+		break;
+
+	case 5:
+		codec_send(REG_EQ5 | ((args->frequency & EQC_MASK) << EQC_POS) | ((args->gain & EQG_MASK) << EQG_POS));
+		break;
+	}
 }
 }
 
 
 // TODO eq1() ~ eq5() are just for testing. To be removed.
 // TODO eq1() ~ eq5() are just for testing. To be removed.
 void eq1(uint8_t freq, uint8_t gain, uint8_t mode)
 void eq1(uint8_t freq, uint8_t gain, uint8_t mode)
 {
 {
-    codec_send(REG_EQ1 | ((freq & EQC_MASK) << EQC_POS) | ((gain & EQG_MASK) << EQG_POS) | (mode ? EQ3DMODE_DAC : EQ3DMODE_ADC));
+	codec_send(REG_EQ1 | ((freq & EQC_MASK) << EQC_POS) | ((gain & EQG_MASK) << EQG_POS) | (mode ? EQ3DMODE_DAC : EQ3DMODE_ADC));
 }
 }
 
 
 void eq2(uint8_t freq, uint8_t gain, uint8_t bw)
 void eq2(uint8_t freq, uint8_t gain, uint8_t bw)
 {
 {
-    codec_send(REG_EQ2 | ((freq & EQC_MASK) << EQC_POS) | ((gain & EQG_MASK) << EQG_POS) | (bw ? EQ2BW_WIDE : EQ2BW_NARROW));
+	codec_send(REG_EQ2 | ((freq & EQC_MASK) << EQC_POS) | ((gain & EQG_MASK) << EQG_POS) | (bw ? EQ2BW_WIDE : EQ2BW_NARROW));
 }
 }
 
 
 void eq3(uint8_t freq, uint8_t gain, uint8_t bw)
 void eq3(uint8_t freq, uint8_t gain, uint8_t bw)
 {
 {
-    codec_send(REG_EQ3 | ((freq & EQC_MASK) << EQC_POS) | ((gain & EQG_MASK) << EQG_POS) | (bw ? EQ3BW_WIDE : EQ3BW_NARROW));
+	codec_send(REG_EQ3 | ((freq & EQC_MASK) << EQC_POS) | ((gain & EQG_MASK) << EQG_POS) | (bw ? EQ3BW_WIDE : EQ3BW_NARROW));
 }
 }
 
 
 void eq4(uint8_t freq, uint8_t gain, uint8_t bw)
 void eq4(uint8_t freq, uint8_t gain, uint8_t bw)
 {
 {
-    codec_send(REG_EQ4 | ((freq & EQC_MASK) << EQC_POS) | ((gain & EQG_MASK) << EQG_POS) | (bw ? EQ4BW_WIDE : EQ4BW_NARROW));
+	codec_send(REG_EQ4 | ((freq & EQC_MASK) << EQC_POS) | ((gain & EQG_MASK) << EQG_POS) | (bw ? EQ4BW_WIDE : EQ4BW_NARROW));
 }
 }
 
 
 void eq5(uint8_t freq, uint8_t gain)
 void eq5(uint8_t freq, uint8_t gain)
 {
 {
-    codec_send(REG_EQ2 | ((freq & EQC_MASK) << EQC_POS) | ((gain & EQG_MASK) << EQG_POS));
+	codec_send(REG_EQ2 | ((freq & EQC_MASK) << EQC_POS) | ((gain & EQG_MASK) << EQG_POS));
 }
 }
 
 
 void eq3d(uint8_t depth)
 void eq3d(uint8_t depth)
 {
 {
-    codec_send(REG_3D | ((depth & DEPTH3D_MASK) << DEPTH3D_POS));
+	codec_send(REG_3D | ((depth & DEPTH3D_MASK) << DEPTH3D_POS));
 }
 }
 
 
 rt_err_t sample_rate(int sr)
 rt_err_t sample_rate(int sr)
 {
 {
-    uint16_t r07 = REG_ADDITIONAL;
+	uint16_t r07 = REG_ADDITIONAL;
 
 
-    switch (sr)
-    {
-    case 8000:
-        r06 = REG_CLOCK_GEN | CLKSEL_MCLK | MCLK_DIV6 | BCLK_DIV8 | (r06 & MS);
-        r07 |= SR_8KHZ;
-        break;
+	switch (sr)
+	{
+	case 8000:
+		r06 = REG_CLOCK_GEN | CLKSEL_MCLK | MCLK_DIV6 | BCLK_DIV8 | (r06 & MS);
+		r07 |= SR_8KHZ;
+		break;
 
 
-    case 11025:
-        r06 = REG_CLOCK_GEN | CLKSEL_PLL | MCLK_DIV8 | BCLK_DIV8 | (r06 & MS);
-        r07 |= SR_12KHZ;
-        break;
+	case 11025:
+		r06 = REG_CLOCK_GEN | CLKSEL_PLL | MCLK_DIV8 | BCLK_DIV8 | (r06 & MS);
+		r07 |= SR_12KHZ;
+		break;
 
 
 #if CODEC_MASTER_MODE
 #if CODEC_MASTER_MODE
-    case 12000:
-        r06 = REG_CLOCK_GEN | CLKSEL_MCLK | MCLK_DIV4 | BCLK_DIV8 | (r06 & MS);
-        r07 |= SR_12KHZ;
-        break;
+	case 12000:
+		r06 = REG_CLOCK_GEN | CLKSEL_MCLK | MCLK_DIV4 | BCLK_DIV8 | (r06 & MS);
+		r07 |= SR_12KHZ;
+		break;
 #endif
 #endif
 
 
-    case 16000:
-        r06 = REG_CLOCK_GEN | CLKSEL_MCLK | MCLK_DIV3 | BCLK_DIV8 | (r06 & MS);
-        r07 |= SR_16KHZ;
-        break;
+	case 16000:
+		r06 = REG_CLOCK_GEN | CLKSEL_MCLK | MCLK_DIV3 | BCLK_DIV8 | (r06 & MS);
+		r07 |= SR_16KHZ;
+		break;
 
 
-    case 22050:
-        r06 = REG_CLOCK_GEN | CLKSEL_PLL | MCLK_DIV4 | BCLK_DIV8 | (r06 & MS);
-        r07 |= SR_24KHZ;
-        break;
+	case 22050:
+		r06 = REG_CLOCK_GEN | CLKSEL_PLL | MCLK_DIV4 | BCLK_DIV8 | (r06 & MS);
+		r07 |= SR_24KHZ;
+		break;
 
 
 #if CODEC_MASTER_MODE
 #if CODEC_MASTER_MODE
-    case 24000:
-        r06 = REG_CLOCK_GEN | CLKSEL_MCLK | MCLK_DIV2 | BCLK_DIV8 | (r06 & MS);
-        r07 |= SR_24KHZ;
-        break;
+	case 24000:
+		r06 = REG_CLOCK_GEN | CLKSEL_MCLK | MCLK_DIV2 | BCLK_DIV8 | (r06 & MS);
+		r07 |= SR_24KHZ;
+		break;
 #endif
 #endif
 
 
-    case 32000:
-        r06 = REG_CLOCK_GEN | CLKSEL_MCLK | MCLK_DIV1_5 | BCLK_DIV8 | (r06 & MS);
-        r07 |= SR_32KHZ;
-        break;
+	case 32000:
+		r06 = REG_CLOCK_GEN | CLKSEL_MCLK | MCLK_DIV1_5 | BCLK_DIV8 | (r06 & MS);
+		r07 |= SR_32KHZ;
+		break;
 
 
-    case 44100:
-        r06 = REG_CLOCK_GEN | CLKSEL_PLL | MCLK_DIV2 | BCLK_DIV8 | (r06 & MS);
-        r07 |= SR_48KHZ;
-        break;
+	case 44100:
+		r06 = REG_CLOCK_GEN | CLKSEL_PLL | MCLK_DIV2 | BCLK_DIV8 | (r06 & MS);
+		r07 |= SR_48KHZ;
+		break;
 
 
-    case 48000:
-        r06 = REG_CLOCK_GEN | CLKSEL_MCLK | MCLK_DIV1 | BCLK_DIV8 | (r06 & MS);
-        r07 |= SR_48KHZ;
-        break;
+	case 48000:
+		r06 = REG_CLOCK_GEN | CLKSEL_MCLK | MCLK_DIV1 | BCLK_DIV8 | (r06 & MS);
+		r07 |= SR_48KHZ;
+		break;
 
 
-    default:
-        return RT_ERROR;
-    }
-    codec_send(r06);
-    codec_send(r07);
+	default:
+		return RT_ERROR;
+	}
+	codec_send(r06);
+	codec_send(r07);
 
 
 #if !CODEC_MASTER_MODE
 #if !CODEC_MASTER_MODE
-    I2S_Configuration((uint32_t) sr);
+	codec_sr_new = sr;
 #endif
 #endif
 
 
-    return RT_EOK;
+	return RT_EOK;
 }
 }
 
 
 FINSH_FUNCTION_EXPORT(vol, Set volume);
 FINSH_FUNCTION_EXPORT(vol, Set volume);
@@ -424,219 +432,226 @@ FINSH_FUNCTION_EXPORT(sample_rate, Set sample rate);
 static rt_err_t codec_open(rt_device_t dev, rt_uint16_t oflag)
 static rt_err_t codec_open(rt_device_t dev, rt_uint16_t oflag)
 {
 {
 #if !CODEC_MASTER_MODE
 #if !CODEC_MASTER_MODE
-    /* enable I2S */
-    I2S_Cmd(CODEC_I2S_PORT, ENABLE);
+	/* enable I2S */
+	I2S_Cmd(CODEC_I2S_PORT, ENABLE);
 #endif
 #endif
 
 
-    return RT_EOK;
+	return RT_EOK;
 }
 }
 
 
 static rt_err_t codec_close(rt_device_t dev)
 static rt_err_t codec_close(rt_device_t dev)
 {
 {
 #if CODEC_MASTER_MODE
 #if CODEC_MASTER_MODE
-    if (r06 & MS)
-    {
-        CODEC_I2S_DMA->CCR &= ~DMA_CCR1_EN;
-        while ((CODEC_I2S_PORT->SR & SPI_I2S_FLAG_TXE) == 0);
-        while ((CODEC_I2S_PORT->SR & SPI_I2S_FLAG_BSY) != 0);
-        CODEC_I2S_PORT->I2SCFGR &= ~SPI_I2SCFGR_I2SE;
-
-        r06 &= ~MS;
-        codec_send(r06);
-
-        /* remove all data node */
-        if (codec.parent.tx_complete != RT_NULL)
-        {
-            rt_base_t level = rt_hw_interrupt_disable();
-
-            do
-            {
-                codec.parent.tx_complete(&codec.parent, codec.data_list[codec.read_index].data_ptr);
-                codec.read_index++;
-                if (codec.read_index >= DATA_NODE_MAX)
-                {
-                    codec.read_index = 0;
-                }
-            }
-            while (codec.read_index != codec.put_index);
-
-            rt_hw_interrupt_enable(level);
-        }
-    }
+	if (r06 & MS)
+	{
+		CODEC_I2S_DMA->CCR &= ~DMA_CCR1_EN;
+		while ((CODEC_I2S_PORT->SR & SPI_I2S_FLAG_TXE) == 0);
+		while ((CODEC_I2S_PORT->SR & SPI_I2S_FLAG_BSY) != 0);
+		CODEC_I2S_PORT->I2SCFGR &= ~SPI_I2SCFGR_I2SE;
+
+		r06 &= ~MS;
+		codec_send(r06);
+
+		/* remove all data node */
+		if (codec.parent.tx_complete != RT_NULL)
+		{
+			rt_base_t level = rt_hw_interrupt_disable();
+
+			do
+			{
+				codec.parent.tx_complete(&codec.parent, codec.data_list[codec.read_index].data_ptr);
+				codec.read_index++;
+				if (codec.read_index >= DATA_NODE_MAX)
+				{
+					codec.read_index = 0;
+				}
+			}
+			while (codec.read_index != codec.put_index);
+
+			rt_hw_interrupt_enable(level);
+		}
+	}
 #endif
 #endif
 
 
-    return RT_EOK;
+	return RT_EOK;
 }
 }
 
 
 static rt_err_t codec_control(rt_device_t dev, rt_uint8_t cmd, void *args)
 static rt_err_t codec_control(rt_device_t dev, rt_uint8_t cmd, void *args)
 {
 {
-    switch (cmd)
-    {
-    case CODEC_CMD_RESET:
-        codec_init(dev);
-        break;
-
-    case CODEC_CMD_VOLUME:
-        vol(*((uint16_t*) args));
-        break;
-
-    case CODEC_CMD_SAMPLERATE:
-        dev->close(dev);
-        sample_rate(*((int*) args));
-        dev->open(dev,0);
-        break;
-
-    case CODEC_CMD_EQ:
-        eq((codec_eq_args_t) args);
-        break;
-
-    case CODEC_CMD_3D:
-        eq3d(*((uint8_t*) args));
-        break;
-
-    default:
-        return RT_ERROR;
-    }
-    return RT_EOK;
+	switch (cmd)
+	{
+	case CODEC_CMD_RESET:
+		codec_init(dev);
+		break;
+
+	case CODEC_CMD_VOLUME:
+		vol(*((uint16_t*) args));
+		break;
+
+	case CODEC_CMD_SAMPLERATE:
+		sample_rate(*((int*) args));
+		break;
+
+	case CODEC_CMD_EQ:
+		eq((codec_eq_args_t) args);
+		break;
+
+	case CODEC_CMD_3D:
+		eq3d(*((uint8_t*) args));
+		break;
+
+	default:
+		return RT_ERROR;
+	}
+	return RT_EOK;
 }
 }
 
 
 static rt_size_t codec_write(rt_device_t dev, rt_off_t pos,
 static rt_size_t codec_write(rt_device_t dev, rt_off_t pos,
-                             const void* buffer, rt_size_t size)
+		const void* buffer, rt_size_t size)
 {
 {
-    struct codec_device* device;
-    struct codec_data_node* node;
-    rt_uint32_t level;
-    rt_uint16_t next_index;
-
-    device = (struct codec_device*) dev;
-    RT_ASSERT(device != RT_NULL);
-
-    next_index = device->put_index + 1;
-    if (next_index >= DATA_NODE_MAX)
-        next_index = 0;
-
-    /* check data_list full */
-    if (next_index == device->read_index)
-    {
-        rt_set_errno(-RT_EFULL);
-        return 0;
-    }
-
-    level = rt_hw_interrupt_disable();
-    node = &device->data_list[device->put_index];
-    device->put_index = next_index;
-
-    /* set node attribute */
-    node->data_ptr = (rt_uint16_t*) buffer;
-    node->data_size = size >> 1; /* size is byte unit, convert to half word unit */
-
-    next_index = device->read_index + 1;
-    if (next_index >= DATA_NODE_MAX)
-        next_index = 0;
-
-    /* check data list whether is empty */
-    if (next_index == device->put_index)
-    {
-        DMA_Configuration((rt_uint32_t) node->data_ptr, node->data_size);
+	struct codec_device* device;
+	struct codec_data_node* node;
+	rt_uint32_t level;
+	rt_uint16_t next_index;
+
+	device = (struct codec_device*) dev;
+	RT_ASSERT(device != RT_NULL);
+
+	next_index = device->put_index + 1;
+	if (next_index >= DATA_NODE_MAX)
+		next_index = 0;
+
+	/* check data_list full */
+	if (next_index == device->read_index)
+	{
+		rt_set_errno(-RT_EFULL);
+		return 0;
+	}
+
+	level = rt_hw_interrupt_disable();
+	node = &device->data_list[device->put_index];
+	device->put_index = next_index;
+
+	/* set node attribute */
+	node->data_ptr = (rt_uint16_t*) buffer;
+	node->data_size = size >> 1; /* size is byte unit, convert to half word unit */
+
+	next_index = device->read_index + 1;
+	if (next_index >= DATA_NODE_MAX)
+		next_index = 0;
+
+	/* check data list whether is empty */
+	if (next_index == device->put_index)
+	{
+		DMA_Configuration((rt_uint32_t) node->data_ptr, node->data_size);
 
 
 #if CODEC_MASTER_MODE
 #if CODEC_MASTER_MODE
-        if ((r06 & MS) == 0)
-        {
-            CODEC_I2S_PORT->I2SCFGR |= SPI_I2SCFGR_I2SE;
-            r06 |= MS;
-            codec_send(r06);
-        }
+		if ((r06 & MS) == 0)
+		{
+			CODEC_I2S_PORT->I2SCFGR |= SPI_I2SCFGR_I2SE;
+			r06 |= MS;
+			codec_send(r06);
+		}
 #endif
 #endif
-    }
-    rt_hw_interrupt_enable(level);
+	}
+	rt_hw_interrupt_enable(level);
 
 
-    return size;
+	return size;
 }
 }
 
 
 rt_err_t codec_hw_init(void)
 rt_err_t codec_hw_init(void)
 {
 {
-    rt_device_t dev;
-
-    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC, ENABLE);
-    RCC_APB1PeriphClockCmd(CODEC_I2S_RCC_APB1, ENABLE);
-    RCC_AHBPeriphClockCmd(CODEC_I2S_RCC_AHB, ENABLE);
-
-    NVIC_Configuration();
-    GPIO_Configuration();
-    I2S_Configuration(I2S_AudioFreq_44k);
-
-    dev = (rt_device_t) &codec;
-    dev->type = RT_Device_Class_Sound;
-    dev->rx_indicate = RT_NULL;
-    dev->tx_complete = RT_NULL;
-    dev->init = codec_init;
-    dev->open = codec_open;
-    dev->close = codec_close;
-    dev->read = RT_NULL;
-    dev->write = codec_write;
-    dev->control = codec_control;
-    dev->private = RT_NULL;
-
-    /* set read_index and put index to 0 */
-    codec.read_index = 0;
-    codec.put_index = 0;
-
-    /* unselect */
-    codec_set_csb();
-
-    /* register the device */
-    return rt_device_register(&codec.parent, "snd", RT_DEVICE_FLAG_WRONLY | RT_DEVICE_FLAG_DMA_TX);
+	rt_device_t dev;
+
+	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC, ENABLE);
+	RCC_APB1PeriphClockCmd(CODEC_I2S_RCC_APB1, ENABLE);
+	RCC_AHBPeriphClockCmd(CODEC_I2S_RCC_AHB, ENABLE);
+
+	NVIC_Configuration();
+	GPIO_Configuration();
+	I2S_Configuration(I2S_AudioFreq_44k);
+
+	dev = (rt_device_t) &codec;
+	dev->type = RT_Device_Class_Sound;
+	dev->rx_indicate = RT_NULL;
+	dev->tx_complete = RT_NULL;
+	dev->init = codec_init;
+	dev->open = codec_open;
+	dev->close = codec_close;
+	dev->read = RT_NULL;
+	dev->write = codec_write;
+	dev->control = codec_control;
+	dev->private = RT_NULL;
+
+	/* set read_index and put index to 0 */
+	codec.read_index = 0;
+	codec.put_index = 0;
+
+	/* unselect */
+	codec_set_csb();
+
+	/* register the device */
+	return rt_device_register(&codec.parent, "snd", RT_DEVICE_FLAG_WRONLY | RT_DEVICE_FLAG_DMA_TX);
 }
 }
 
 
 void codec_dma_isr(void)
 void codec_dma_isr(void)
 {
 {
-    /* switch to next buffer */
-    rt_uint16_t next_index;
-    void* data_ptr;
+	/* switch to next buffer */
+	rt_uint16_t next_index;
+	void* data_ptr;
+
+	next_index = codec.read_index + 1;
+	if (next_index >= DATA_NODE_MAX)
+		next_index = 0;
 
 
-    next_index = codec.read_index + 1;
-    if (next_index >= DATA_NODE_MAX)
-        next_index = 0;
+	/* save current data pointer */
+	data_ptr = codec.data_list[codec.read_index].data_ptr;
 
 
-    /* save current data pointer */
-    data_ptr = codec.data_list[codec.read_index].data_ptr;
+#if !CODEC_MASTER_MODE
+	if (codec_sr_new)
+	{
+		I2S_Configuration(codec_sr_new);
+		I2S_Cmd(CODEC_I2S_PORT, ENABLE);
+		codec_sr_new = 0;
+	}
+#endif
 
 
-    codec.read_index = next_index;
-    if (next_index != codec.put_index)
-    {
-        /* enable next dma request */
-        DMA_Configuration((rt_uint32_t) codec.data_list[codec.read_index].data_ptr, codec.data_list[codec.read_index].data_size);
+	codec.read_index = next_index;
+	if (next_index != codec.put_index)
+	{
+		/* enable next dma request */
+		DMA_Configuration((rt_uint32_t) codec.data_list[codec.read_index].data_ptr, codec.data_list[codec.read_index].data_size);
 
 
 #if CODEC_MASTER_MODE
 #if CODEC_MASTER_MODE
-        if ((r06 & MS) == 0)
-        {
-            CODEC_I2S_PORT->I2SCFGR |= SPI_I2SCFGR_I2SE;
-            r06 |= MS;
-            codec_send(r06);
-        }
+		if ((r06 & MS) == 0)
+		{
+			CODEC_I2S_PORT->I2SCFGR |= SPI_I2SCFGR_I2SE;
+			r06 |= MS;
+			codec_send(r06);
+		}
 #endif
 #endif
-    }
-    else
-    {
+	}
+	else
+	{
 #if CODEC_MASTER_MODE
 #if CODEC_MASTER_MODE
-        if (r06 & MS)
-        {
-            CODEC_I2S_DMA->CCR &= ~DMA_CCR1_EN;
-            while ((CODEC_I2S_PORT->SR & SPI_I2S_FLAG_TXE) == 0);
-            while ((CODEC_I2S_PORT->SR & SPI_I2S_FLAG_BSY) != 0);
-            CODEC_I2S_PORT->I2SCFGR &= ~SPI_I2SCFGR_I2SE;
-
-            r06 &= ~MS;
-            codec_send(r06);
-        }
+		if (r06 & MS)
+		{
+			CODEC_I2S_DMA->CCR &= ~DMA_CCR1_EN;
+			while ((CODEC_I2S_PORT->SR & SPI_I2S_FLAG_TXE) == 0);
+			while ((CODEC_I2S_PORT->SR & SPI_I2S_FLAG_BSY) != 0);
+			CODEC_I2S_PORT->I2SCFGR &= ~SPI_I2SCFGR_I2SE;
+
+			r06 &= ~MS;
+			codec_send(r06);
+		}
 #endif
 #endif
 
 
-        rt_kprintf("*\n");
-    }
+		rt_kprintf("*\n");
+	}
 
 
-    /* notify transmitted complete. */
-    if (codec.parent.tx_complete != RT_NULL)
-    {
-        codec.parent.tx_complete(&codec.parent, data_ptr);
-    }
+	/* notify transmitted complete. */
+	if (codec.parent.tx_complete != RT_NULL)
+	{
+		codec.parent.tx_complete(&codec.parent, data_ptr);
+	}
 }
 }

+ 213 - 57
bsp/stm32_radio/spi_flash.c

@@ -1,8 +1,22 @@
 #include <stm32f10x.h>
 #include <stm32f10x.h>
+#include "board.h"
 #include "spi_flash.h"
 #include "spi_flash.h"
 #include "rtthread.h"
 #include "rtthread.h"
 
 
-extern unsigned char SPI_WriteByte(unsigned char data);
+/*
+ * WARNING: !!! ENABLING DMA MODE MAY DESTROY YOUR DATA IN THE SPI FLASH !!!
+ * Don't set SPI_FLASH_USE_DMA to 1 unless you know what you're doing!
+ * However, readonly access is just fine. :)
+ */
+#define SPI_FLASH_USE_DMA	0
+#define SECTOR_SIZE			512
+
+extern uint8_t SPI_WriteByte(unsigned char data);
+
+#if SPI_FLASH_USE_DMA
+static uint8_t dummy = 0;
+static uint8_t _spi_flash_buffer[SECTOR_SIZE];
+#endif
 
 
 /********************** hardware *************************************/
 /********************** hardware *************************************/
 /* SPI_FLASH_CS   PA4 */
 /* SPI_FLASH_CS   PA4 */
@@ -18,19 +32,102 @@ static void GPIO_Configuration(void)
 {
 {
     GPIO_InitTypeDef GPIO_InitStructure;
     GPIO_InitTypeDef GPIO_InitStructure;
 
 
-    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
+    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
 
 
     GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_4 | GPIO_Pin_3;
     GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_4 | GPIO_Pin_3;
     GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_Out_PP;
     GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_Out_PP;
-    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
-    GPIO_Init(GPIOA,&GPIO_InitStructure);
+    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
+    GPIO_Init(GPIOA, &GPIO_InitStructure);
 
 
     FLASH_RST_0(); // RESET
     FLASH_RST_0(); // RESET
     FLASH_CS_1();
     FLASH_CS_1();
     FLASH_RST_1();
     FLASH_RST_1();
 }
 }
 
 
-static unsigned char SPI_HostReadByte(void)
+#if SPI_FLASH_USE_DMA
+static void DMA_RxConfiguration(rt_uint32_t addr, rt_size_t size)
+{
+    DMA_InitTypeDef DMA_InitStructure;
+
+    DMA_ClearFlag(DMA1_FLAG_TC2 | DMA1_FLAG_TE2 | DMA1_FLAG_TC3 | DMA1_FLAG_TE3);
+    dummy = 0;
+
+	/* DMA Channel configuration ----------------------------------------------*/
+	DMA_Cmd(DMA1_Channel2, DISABLE);
+	DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)(&(SPI1->DR));
+	DMA_InitStructure.DMA_MemoryBaseAddr = (u32) addr;
+	DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
+	DMA_InitStructure.DMA_BufferSize = size;
+	DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
+	DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
+	DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
+	DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
+	DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;
+	DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
+	DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
+	DMA_Init(DMA1_Channel2, &DMA_InitStructure);
+
+	DMA_Cmd(DMA1_Channel2, ENABLE);
+
+	/* Dummy TX channel configuration */
+	DMA_Cmd(DMA1_Channel3, DISABLE);
+	DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)(&(SPI1->DR));
+	DMA_InitStructure.DMA_MemoryBaseAddr = (u32)(&dummy);
+	DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
+	DMA_InitStructure.DMA_BufferSize = size;
+	DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
+	DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Disable;
+	DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
+	DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
+	DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;
+	DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
+	DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
+	DMA_Init(DMA1_Channel3, &DMA_InitStructure);
+
+	DMA_Cmd(DMA1_Channel3, ENABLE);
+}
+
+static void DMA_TxConfiguration(rt_uint32_t addr, rt_size_t size)
+{
+    DMA_InitTypeDef DMA_InitStructure;
+
+    DMA_ClearFlag(DMA1_FLAG_TC2 | DMA1_FLAG_TE2 | DMA1_FLAG_TC3 | DMA1_FLAG_TE3);
+
+	/* DMA Channel configuration ----------------------------------------------*/
+	DMA_Cmd(DMA1_Channel2, DISABLE);
+	DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)(&(SPI1->DR));
+	DMA_InitStructure.DMA_MemoryBaseAddr = (u32)(&dummy);
+	DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
+	DMA_InitStructure.DMA_BufferSize = size;
+	DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
+	DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Disable;
+	DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
+	DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
+	DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;
+	DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
+	DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
+	DMA_Init(DMA1_Channel2, &DMA_InitStructure);
+
+    /* DMA Channel configuration ----------------------------------------------*/
+	DMA_Cmd(DMA1_Channel3, DISABLE);
+	DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)(&(SPI1->DR));
+	DMA_InitStructure.DMA_MemoryBaseAddr = (u32) addr;
+	DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
+	DMA_InitStructure.DMA_BufferSize = size;
+	DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
+	DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
+	DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
+	DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
+	DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;
+	DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
+	DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
+	DMA_Init(DMA1_Channel3, &DMA_InitStructure);
+
+	DMA_Cmd(DMA1_Channel3, ENABLE);
+}
+#endif
+
+static uint8_t SPI_HostReadByte(void)
 {
 {
     //return SPI_WriteByte(0x00);
     //return SPI_WriteByte(0x00);
     //Wait until the transmit buffer is empty
     //Wait until the transmit buffer is empty
@@ -47,7 +144,7 @@ static unsigned char SPI_HostReadByte(void)
 
 
 }
 }
 
 
-static void SPI_HostWriteByte(unsigned char wByte)
+static void SPI_HostWriteByte(uint8_t wByte)
 {
 {
     SPI_WriteByte(wByte);
     SPI_WriteByte(wByte);
 }
 }
@@ -63,13 +160,13 @@ static void SPI_HostWriteByte(unsigned char wByte)
 /* 1:ready  |        |        AT45DB161:1011             |                   */
 /* 1:ready  |        |        AT45DB161:1011             |                   */
 /* --------------------------------------------------------------------------*/
 /* --------------------------------------------------------------------------*/
 /*****************************************************************************/
 /*****************************************************************************/
-static unsigned char AT45DB_StatusRegisterRead(void)
+static uint8_t AT45DB_StatusRegisterRead(void)
 {
 {
-    unsigned char i;
+    uint8_t i;
 
 
     FLASH_CS_0();
     FLASH_CS_0();
     SPI_HostWriteByte(AT45DB_READ_STATE_REGISTER);
     SPI_HostWriteByte(AT45DB_READ_STATE_REGISTER);
-    i=SPI_HostReadByte();
+    i = SPI_HostReadByte();
     FLASH_CS_1();
     FLASH_CS_1();
 
 
     return i;
     return i;
@@ -77,74 +174,122 @@ static unsigned char AT45DB_StatusRegisterRead(void)
 
 
 static void wait_busy(void)
 static void wait_busy(void)
 {
 {
-    unsigned int    i=0;
-    while (i++<3000)
+    uint16_t i = 0;
+    while (i++ < 10000)
     {
     {
-        if (AT45DB_StatusRegisterRead()&0x80)
+        if (AT45DB_StatusRegisterRead() & 0x80)
         {
         {
-            break;
+            return;
         }
         }
     }
     }
-    if( !(i<3000) )
-    {
-        rt_kprintf("\r\nSPI_FLASH timeout!!!");
-    }
+    rt_kprintf("\r\nSPI_FLASH timeout!!!\r\n");
 }
 }
 
 
-static void read_page(unsigned int page,unsigned char * pHeader)
+static void read_page(uint32_t page, uint8_t *pHeader)
 {
 {
-    unsigned int i=0;
+#if SPI_FLASH_USE_DMA
+    rt_sem_take(&spi1_lock, RT_WAITING_FOREVER);
 
 
-    wait_busy();
+	DMA_RxConfiguration((rt_uint32_t) pHeader, SECTOR_SIZE);
 
 
     FLASH_CS_0();
     FLASH_CS_0();
-    SPI_HostWriteByte(AT45DB_MM_PAGE_TO_B1_XFER);
-    SPI_HostWriteByte((unsigned char)(page >> 6));
-    SPI_HostWriteByte((unsigned char)(page << 2));
+
+    SPI_HostWriteByte(AT45DB_MM_PAGE_READ);
+    SPI_HostWriteByte((uint8_t)(page >> 6));
+    SPI_HostWriteByte((uint8_t)(page << 2));
     SPI_HostWriteByte(0x00);
     SPI_HostWriteByte(0x00);
-    FLASH_CS_1();
 
 
-    wait_busy();
+    // 4 don't care bytes
+    SPI_HostWriteByte(0x00);
+    SPI_HostWriteByte(0x00);
+    SPI_HostWriteByte(0x00);
+    SPI_HostWriteByte(0x00);
+
+	SPI_I2S_ClearFlag(SPI1, SPI_I2S_FLAG_RXNE);
+	SPI_I2S_DMACmd(SPI1, SPI_I2S_DMAReq_Tx | SPI_I2S_DMAReq_Rx, ENABLE);
+	while (DMA_GetFlagStatus(DMA1_FLAG_TC2) == RESET);
+
+	FLASH_CS_1();
+
+	SPI_I2S_DMACmd(SPI1, SPI_I2S_DMAReq_Tx | SPI_I2S_DMAReq_Rx, DISABLE);
+
+	rt_sem_release(&spi1_lock);
+#else
+    uint16_t i;
+
+    rt_sem_take(&spi1_lock, RT_WAITING_FOREVER);
 
 
     FLASH_CS_0();
     FLASH_CS_0();
-    SPI_HostWriteByte(AT45DB_BUFFER_1_READ);
+
+    SPI_HostWriteByte(AT45DB_MM_PAGE_READ);
+    SPI_HostWriteByte((uint8_t)(page >> 6));
+    SPI_HostWriteByte((uint8_t)(page << 2));
     SPI_HostWriteByte(0x00);
     SPI_HostWriteByte(0x00);
+
+    // 4 don't care bytes
     SPI_HostWriteByte(0x00);
     SPI_HostWriteByte(0x00);
     SPI_HostWriteByte(0x00);
     SPI_HostWriteByte(0x00);
     SPI_HostWriteByte(0x00);
     SPI_HostWriteByte(0x00);
-    for (i=0; i<512; i++)
-    {
-        *pHeader++ = SPI_HostReadByte();
-    }
-    FLASH_CS_1();
+    SPI_HostWriteByte(0x00);
+
+	for (i = 0; i < SECTOR_SIZE; i++)
+	{
+		*pHeader++ = SPI_HostReadByte();
+	}
+
+	FLASH_CS_1();
 
 
+    rt_sem_release(&spi1_lock);
+#endif
 }
 }
 
 
-static void write_page(unsigned int page,unsigned char * pHeader)
+static void write_page(uint32_t page, uint8_t *pHeader)
 {
 {
-    unsigned int i;
+#if SPI_FLASH_USE_DMA
+    rt_sem_take(&spi1_lock, RT_WAITING_FOREVER);
+
+    DMA_TxConfiguration((rt_uint32_t) pHeader, SECTOR_SIZE);
+
+    FLASH_CS_0();
+
+    SPI_HostWriteByte(AT45DB_MM_PAGE_PROG_THRU_BUFFER1);
+    SPI_HostWriteByte((uint8_t) (page >> 6));
+    SPI_HostWriteByte((uint8_t) (page << 2));
+    SPI_HostWriteByte(0x00);
+
+	SPI_I2S_DMACmd(SPI1, SPI_I2S_DMAReq_Tx, ENABLE);
+	while (DMA_GetFlagStatus(DMA1_FLAG_TC3) == RESET);
+
+	FLASH_CS_1();
+
+    SPI_I2S_DMACmd(SPI1, SPI_I2S_DMAReq_Tx, DISABLE);
 
 
     wait_busy();
     wait_busy();
 
 
+    rt_sem_release(&spi1_lock);
+#else
+    uint16_t i;
+
+    rt_sem_take(&spi1_lock, RT_WAITING_FOREVER);
+
     FLASH_CS_0();
     FLASH_CS_0();
-    SPI_HostWriteByte(AT45DB_BUFFER_2_WRITE);
-    SPI_HostWriteByte(0);
-    SPI_HostWriteByte(0);
-    SPI_HostWriteByte(0);
-    for(i=0; i<512; i++)
+
+    SPI_HostWriteByte(AT45DB_MM_PAGE_PROG_THRU_BUFFER1);
+    SPI_HostWriteByte((uint8_t) (page >> 6));
+    SPI_HostWriteByte((uint8_t) (page << 2));
+    SPI_HostWriteByte(0x00);
+
+    for (i = 0; i < SECTOR_SIZE; i++)
     {
     {
         SPI_HostWriteByte(*pHeader++);
         SPI_HostWriteByte(*pHeader++);
     }
     }
+
     FLASH_CS_1();
     FLASH_CS_1();
 
 
     wait_busy();
     wait_busy();
 
 
-    FLASH_CS_0();
-    SPI_HostWriteByte(AT45DB_B2_TO_MM_PAGE_PROG_WITH_ERASE);
-    SPI_HostWriteByte((unsigned char)(page>>6));
-    SPI_HostWriteByte((unsigned char)(page<<2));
-    SPI_HostWriteByte(0x00);
-    FLASH_CS_1();
+    rt_sem_release(&spi1_lock);
+#endif
 }
 }
 
 
 
 
@@ -176,42 +321,53 @@ static rt_err_t rt_spi_flash_control(rt_device_t dev, rt_uint8_t cmd, void *args
 
 
 static rt_size_t rt_spi_flash_read(rt_device_t dev, rt_off_t pos, void* buffer, rt_size_t size)
 static rt_size_t rt_spi_flash_read(rt_device_t dev, rt_off_t pos, void* buffer, rt_size_t size)
 {
 {
-    rt_uint8_t *ptr;
     rt_uint32_t index, nr;
     rt_uint32_t index, nr;
 
 
-    nr = size/512;
-    ptr = (rt_uint8_t*)buffer;
+    nr = size / SECTOR_SIZE;
 
 
-    for (index = 0; index < nr; index ++)
+    for (index = 0; index < nr; index++)
     {
     {
         /* only supply single block read: block size 512Byte */
         /* only supply single block read: block size 512Byte */
-        read_page((pos + index * 512)/512, &ptr[index * 512]);
+#if SPI_FLASH_USE_DMA
+        read_page((pos / SECTOR_SIZE + index), _spi_flash_buffer);
+    	rt_memcpy(((rt_uint8_t *) buffer + index * SECTOR_SIZE), _spi_flash_buffer, SECTOR_SIZE);
+#else
+        read_page((pos / SECTOR_SIZE + index), ((rt_uint8_t *) buffer + index * SECTOR_SIZE));
+#endif
     }
     }
 
 
-    return nr * 512;
+    return nr * SECTOR_SIZE;
 }
 }
 
 
-static rt_size_t rt_spi_flash_write (rt_device_t dev, rt_off_t pos, const void* buffer, rt_size_t size)
+static rt_size_t rt_spi_flash_write(rt_device_t dev, rt_off_t pos, const void* buffer, rt_size_t size)
 {
 {
-    rt_uint8_t *ptr;
     rt_uint32_t index, nr;
     rt_uint32_t index, nr;
 
 
-    nr = size / 512;
-    ptr = (rt_uint8_t*)buffer;
+    nr = size / SECTOR_SIZE;
 
 
-    for (index = 0; index < nr; index ++)
+    for (index = 0; index < nr; index++)
     {
     {
         /* only supply single block write: block size 512Byte */
         /* only supply single block write: block size 512Byte */
-        write_page((pos + index * 512)/512, &ptr[index * 512]);
+#if SPI_FLASH_USE_DMA
+    	rt_memcpy(_spi_flash_buffer, ((rt_uint8_t *) buffer + index * SECTOR_SIZE), SECTOR_SIZE);
+        write_page((pos / SECTOR_SIZE + index), _spi_flash_buffer);
+#else
+        write_page((pos / SECTOR_SIZE + index), ((rt_uint8_t *) buffer + index * SECTOR_SIZE));
+#endif
     }
     }
 
 
-    return nr * 512;
+    return nr * SECTOR_SIZE;
 }
 }
 
 
 void rt_hw_spi_flash_init(void)
 void rt_hw_spi_flash_init(void)
 {
 {
     GPIO_Configuration();
     GPIO_Configuration();
 
 
+#if SPI_FLASH_USE_DMA
+    /* Enable the DMA1 Clock */
+    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
+#endif
+
     /* register spi_flash device */
     /* register spi_flash device */
     spi_flash_device.type    = RT_Device_Class_Block;
     spi_flash_device.type    = RT_Device_Class_Block;
     spi_flash_device.init    = rt_spi_flash_init;
     spi_flash_device.init    = rt_spi_flash_init;

+ 2 - 1
bsp/stm32_radio/spi_flash.h

@@ -18,7 +18,8 @@ thanks to gxlujd.
 #define AT45DB_PAGE_ERASE                     0x81	/* 页删除(每页512/528字节) */
 #define AT45DB_PAGE_ERASE                     0x81	/* 页删除(每页512/528字节) */
 #define AT45DB_SECTOR_ERASE                   0x7C	/* 扇区擦除(每扇区128K字节)*/
 #define AT45DB_SECTOR_ERASE                   0x7C	/* 扇区擦除(每扇区128K字节)*/
 #define AT45DB_READ_STATE_REGISTER            0xD7	/* 读取状态寄存器 */
 #define AT45DB_READ_STATE_REGISTER            0xD7	/* 读取状态寄存器 */
-
+#define AT45DB_MM_PAGE_READ                   0xD2	/* 读取主储存器的指定页 */
+#define AT45DB_MM_PAGE_PROG_THRU_BUFFER1      0x82  /* 通过缓冲区写入主储存器 */
 
 
 extern void rt_hw_spi_flash_init(void);
 extern void rt_hw_spi_flash_init(void);