一步一步和我一起走,进入缤纷的嵌入式世界(连载5)
来源:互联网 发布:教唱歌的软件 编辑:程序博客网 时间:2024/05/02 02:05
上次说到系统的总体架构设计,今天说一说具体的关键点设计。
先看类型定义:
typedef unsigned char U8;
typedef signed char I8;
typedef I8 S8;
typedef unsigned short U16;
typedef signed short I16;
typedef I16 S16;
typedef unsigned long U32;
typedef signed long I32;
typedef I32 S32;
typedef U8 BOOL;
再看 main 函数代码:
int main(void)
{
/*初始化系统时钟*/
SysCtlClockSet(SYSCTL_SYSDIV_10 | SYSCTL_USE_PLL | SYSCTL_OSC_MAIN |
SYSCTL_XTAL_6MHZ);
UART_Init();/*初始化UART*/
SPI_Init();/*初始化SPI*/
DAC_Init();/*初始化解码器*/
InitIOCmd();/*初始化键盘*/
while (1)
{
PlayServiceLoop(); /*播放循环*/
UARTCmdResponse(); /*UART口命令响应*/
IOCmdResponse(); /*IO口的命令响应*/
}
return (0);
}
整个软件的核心设计在于ADPCM的解码和输出,那么就看看核心的ADPCM解码代码和输出代码:
/********************************Copyright(c)********************************
* Xu Xuesong Software Studio
*
* baconxu@gmail.com
*
*
*--------------File Info-----------------------------------------------------
* File Name: dacCtrl.c
* Last modifyed Data: 2007/1/17
* Last Version: V1.0
* Description:
*
*-------------------------------------------------------------------------
* Created By: Bacon Xu
* Created date: 2007/1/17
* Version: V1.0
* Descriptions:
*
*-------------------------------------------------------------------------
* Modified by:
* Modified date: 2007/1/17
* Version:
* Description:
*
*************************************************************************/
/****************************************************************************
* Include Files
****************************************************************************/
#include "../hw_ints.h"
#include "../hw_memmap.h"
#include "../hw_types.h"
#include "../src/gpio.h"
#include "../src/sysctl.h"
#include "../src/ssi.h"
#include "../src/timer.h"
#include "../src/interrupt.h"
#include "GlobalDef.h"
#include "dacCtrl.h"
#include "spi_flash.h"
#include "spi_flash_bsp.h"
#include "uart.h"
/****************************************************************************
* Manifest Constant
****************************************************************************/
const S16 StepTable[89] = {
7, 8, 9, 10, 11, 12, 13, 14, 16, 17,
19, 21, 23, 25, 28, 31, 34, 37, 41, 45,
50, 55, 60, 66, 73, 80, 88, 97, 107, 118,
130, 143, 157, 173, 190, 209, 230, 253, 279, 307,
337, 371, 408, 449, 494, 544, 598, 658, 724, 796,
876, 963, 1060, 1166, 1282, 1411, 1552, 1707, 1878, 2066,
2272, 2499, 2749, 3024, 3327, 3660, 4026, 4428, 4871, 5358,
5894, 6484, 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899,
15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767
};
const S16 IndexAdjust[16] = {
-1, -1, -1, -1, 2, 4, 6, 8,
-1, -1, -1, -1, 2, 4, 6, 8
};
/****************************************************************************
* Macros
****************************************************************************/
#define DAC_DATA_BAUDRATE 10000000 //don't exceed 10000000(10MHz)
#define DAC_DATA_BIT_WIDTH 16
#define DAC_DELAY 6
#define DAC_MUSIC_SAMPLE_RATE 22050
#define DAC_AUDIO_BUFFER_SIZE 64
/****************************************************************************
* Local Types
****************************************************************************/
/****************************************************************************
* Static Variables
****************************************************************************/
static U8 AudioBufferUsed = 0;
static U8 AudioBufferHeader = 0;
static U16 AudioOutBuffer[DAC_AUDIO_BUFFER_SIZE];
PlayState CurPlayState = STOP;
static U32 AudioDataLength = 0;
static I32 Index = 0;
static I32 PrevSample = 0;
static U32 TimeLine = 0;
/****************************************************************************
* Internal Function Phototypes
****************************************************************************/
static void InitDecoder();
static void DecoderByte(U8 inData);
static BOOL AddToAudioOutBuffer(U16 value);
/*--------------------------------------------------------------------------
* Function:
* DAC_Init
*
* Parameters:
* N/A
*
* Returns value:
* N/A
*
* Description:
* Initialize the mcu's peripheral device.
*
*--------------------------------------------------------------------------*/
void DAC_Init(void)
{
SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);
SysCtlPeripheralEnable(SYSCTL_PERIPH_SSI);
GPIODirModeSet(GPIO_PORTB_BASE, GPIO_PIN_2,
GPIO_DIR_MODE_OUT);
SSIConfig(SSI_BASE, SSI_FRF_MOTO_MODE_0, SSI_MODE_MASTER,
DAC_DATA_BAUDRATE, DAC_DATA_BIT_WIDTH);
SSIEnable(SSI_BASE);
GPIODirModeSet(GPIO_PORTA_BASE, (GPIO_PIN_2 |
GPIO_PIN_3 |
GPIO_PIN_4 |
GPIO_PIN_5),
GPIO_DIR_MODE_HW);
SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER0);
IntMasterEnable();
TimerConfigure(TIMER0_BASE, TIMER_CFG_32_BIT_PER);
TimerLoadSet(TIMER0_BASE, TIMER_A,
SysCtlClockGet() / DAC_MUSIC_SAMPLE_RATE);
TimerIntEnable(TIMER0_BASE, TIMER_TIMA_TIMEOUT);
TimerEnable(TIMER0_BASE, TIMER_A);
IntEnable(INT_TIMER0A);
}
/*--------------------------------------------------------------------------
* Function:
* DAC_OutData
*
* Parameters:
* U32 inData the data out to DAC
*
* Returns value:
* N/A
*
* Description:
* Export data to DAC.
*
*--------------------------------------------------------------------------*/
void DAC_OutData(U32 inData)
{
U32 delay;
DAC_Right_Ch();
SSIDataPut(SSI_BASE, inData);
delay = DAC_DELAY;
while (delay--);
DAC_Left_Ch();
SSIDataPut(SSI_BASE, inData);
delay = DAC_DELAY;
while (delay--);
}
void DAC_AudioCallBack(void)
{
TimerIntClear(TIMER0_BASE, TIMER_TIMA_TIMEOUT);
if (AudioBufferUsed)
{
DAC_OutData(AudioOutBuffer[AudioBufferHeader]);
AudioBufferHeader = (AudioBufferHeader + 1) % DAC_AUDIO_BUFFER_SIZE;
AudioBufferUsed--;
}
}
/*
BOOL AddToAudioOutBuffer(U8 inHiByte, U8 inLoByte)
{
IntDisable(INT_TIMER0A);
if (DAC_AUDIO_BUFFER_SIZE > AudioBufferUsed)
{
U16 value;
U8 Index;
value = (((U16)inHiByte << 8) & 0xFF00) | ((U16)inLoByte & 0x00FF);
Index = (AudioBufferHeader + AudioBufferUsed) % DAC_AUDIO_BUFFER_SIZE;
AudioOutBuffer[Index] = value;
AudioBufferUsed++;
IntEnable(INT_TIMER0A);
return (TRUE);
}
IntEnable(INT_TIMER0A);
return (FALSE);
}
*/
BOOL DAC_BufferIsSpaceAvail(void)
{
return (DAC_AUDIO_BUFFER_SIZE - AudioBufferUsed);
}
PlayState GetPlayState()
{
return (CurPlayState);
}
void SetPlayState(PlayState inState)
{
if (CurPlayState == inState)
return ;
switch (CurPlayState)
{
case PLAY:
if (inState != PLAY)
{
if (inState == STOP)
{
SPI_Deselected();
CurPlayState = STOP;
}
else if (inState == PAUSE)
{
CurPlayState = PAUSE;
}
}
break;
case STOP:
if (inState == PLAY)
{
InitPlayState();
CurPlayState = PLAY;
}
break;
case PAUSE:
if (inState == PLAY)
CurPlayState = PLAY;
else if (inState == STOP)
{
CurPlayState = STOP;
SPI_Deselected();
}
default:
break;
}
}
void InitPlayState()
{
SPI_Deselected();
InitDecoder();
SPI_Selected();
TimeLine = 0;
SPI_M25P32_ReadFrom(0x00);
AudioDataLength = 0;
AudioDataLength |= SPI_ReadByte();
AudioDataLength |= (SPI_ReadByte() << 8);
AudioDataLength |= (SPI_ReadByte() << 16);
AudioDataLength |= (SPI_ReadByte() << 24);
dbg_out_endl();
dbg_out_text("Play Audio Length:");
dbg_out_uint(AudioDataLength);
dbg_out_text("Bytes");
dbg_out_endl();
}
void PlayServiceLoop()
{
if (CurPlayState == PLAY)
{
DecoderByte(SPI_ReadByte());
TimeLine ++;
if (TimeLine > AudioDataLength)
{
//dbg_out_uint(TimeLine);
//dbg_out_endl();
SetPlayState(STOP);
//InitPlayState();
GPIO_B_PIN_3 = 0x00;
for (int i = 0; i < 400000; i++);
GPIO_B_PIN_3 = 0xFF;
}
}
}
void InitDecoder()
{
Index = 0;
PrevSample = 0;
}
void DecoderByte(U8 inData)
{
int sign; /* Current adpcm sign bit */
int delta; /* Current adpcm output value */
int step; /* Stepsize */
int vpdiff; /* Current change to valpred */
int i;
for (i = 0; i < 2; i++)
{
/* Step 1 - Update step value */
step = StepTable[Index];
/* Step 2 - get the delta value */
if (i)
delta = inData & 0xF;
else
delta = (inData >> 4) & 0xF;
/* Step 3 - Find new index value (for later) */
Index += IndexAdjust[delta];
if (Index < 0)
Index = 0;
else if (Index > 88)
Index = 88;
/* Step 4 - Separate sign and magnitude */
sign = delta & 0x08;
delta = delta & 0x07;
/* Step 5 - Compute difference and new predicted value */
vpdiff = (delta * step + step >> 1) >> 2;
//vpdiff = delta * step >> 2;
if (sign)
PrevSample -= vpdiff;
else
PrevSample += vpdiff;
/* Step 6 - clamp output value */
if (PrevSample > 32767)
PrevSample = 32767;
else if (PrevSample < -32768)
PrevSample = -32768;
/* Step 7 - Output value */
while (!DAC_BufferIsSpaceAvail());
AddToAudioOutBuffer(PrevSample);
}
}
BOOL AddToAudioOutBuffer(U16 value)
{
IntDisable(INT_TIMER0A);
if (DAC_AUDIO_BUFFER_SIZE > AudioBufferUsed)
{
U8 Index;
Index = (AudioBufferHeader + AudioBufferUsed) % DAC_AUDIO_BUFFER_SIZE;
AudioOutBuffer[Index] = value;
AudioBufferUsed++;
IntEnable(INT_TIMER0A);
return (TRUE);
}
IntEnable(INT_TIMER0A);
return (FALSE);
}
还有一个核心部分是软件的SPI设计,由于考虑到速度问题,使用汇编完成一个字节的读或者写。Cortex-M3的核心只支持Thumb2指令,不支持ARM指令。具体代码如下:
EXPORT SPI_SendByte
EXPORT SPI_ReadByte
SPI_WRITE EQU 0x40005040
SPI_READ EQU 0x40005100
SPI_CLOCK EQU 0x40005080
RSEG CODE
CODE16
SPI_SendByte
;R0 - Send Byte Parameter
PUSH {R1-R5, LR}
CPSID I ;disable interrupt
LDR R1, =SPI_WRITE
LDR R4, =SPI_CLOCK
MOV R5, #0xFF ;R5 = 0xFF
BIC R3, R3 ;R3 = 0, for (R3 = 0; R3 < 8; R3++)
send_loop
MOV R2, #0x80
LSR R2, R3
TST R0, R2
BEQ send_logic_0
STR R5, [R1, #0x00] ;set SPI_WRITE
B send_next
send_logic_0
BIC R2, R2
STR R2, [R1, #0x00] ;clear SPI_WRITE
send_next
STR R5, [R4, #0x00] ;set SPI_CLOCK
BIC R2, R2
STR R2, [R4, #0x00] ;clear SPI_CLOCK
ADD R3, R3, #0x01 ;for (R3 = 0; R3 < 8; R3++)
CMP R3, #0x08
BNE send_loop
BIC R2, R2
STR R2, [R1, #0x00] ;clear SPI_WRITE
CPSIE I ;enable interrupt
POP {R1-R5, PC} ;return
SPI_ReadByte
PUSH {R1-R5, LR}
CPSID I ;disable interrupt
BIC R0, R0
MOV R3, #0x00
LDR R1, =SPI_READ
LDR R2, =SPI_CLOCK
read_loop
MOV R4, #0xFF ;set SPI_CLOCK
STR R4, [R2, #0x00]
LDR R5, [R1, #0x00] ;read status of SPI_READ
BIC R4, R4 ;R4 = 0
STR R4, [R2, #0x00] ;clear SPI_CLOCK
AND R5, R5 ;if (R5 == 0) Goto read_next
BEQ read_next
MOV R4, #0x80
LSR R4, R3
ORR R0, R4
read_next
ADD R3, R3, #0x01 ;for (R3 = 0; R3 < 8; R3++)
CMP R3, #0x08
BNE read_loop
CPSIE I ;enable interrupt
POP {R1-R5, PC} ;return (R0)
END
这里,只贴出了核心的代码,如果有朋友感兴趣可以跟帖索要全部代码。下次我们侃侃其他方面的设计。
- 一步一步和我一起走,进入缤纷的嵌入式世界(连载5)
- 一步一步和我一起走,进入缤纷的嵌入式世界(连载6)
- 一步一步和我走,进入缤纷的嵌入式世界(连载1)
- 一步一步和我走,进入缤纷的嵌入式世界(连载2)
- 一步一步和我走,进入缤纷的嵌入式世界(连载3)
- 一步一步和我走,进入缤纷的嵌入式世界(连载4)
- 来吧,和我一起进入ubuntu 9.04 超级兔子的世界(解决NTFS挂载问题)
- 来吧,一起进入花瓣的世界
- 土豆和西红柿根本就不是一个世界的但是他们走到了一起
- 让我们一起进入haXe的奇幻世界吧
- 初识python django, 让我们一起进入python的世界吧
- 缤纷乐——我的快乐
- 篇1:进入嵌入式世界
- 移动互联网的新宠:Android之缤纷世界
- 我和我的世界
- 他和她的缤纷颜色
- 两个不同世界的人,是注定走不到一起的
- 一步一步进入React的世界(React+Webpack+ES6组合配置)
- 《死亡诗社》影评(作业)
- 重新加载winfrom 中的窗体
- 关于div的position属性
- 最简单的ARM裸机程序,帮你理解程序的运行启动(mini2440开发板)
- 用C#做开发框架
- 一步一步和我一起走,进入缤纷的嵌入式世界(连载5)
- 早睡早起,有益身体
- 服务器Select模型的实现
- 有一类教授
- Ubuntu 8.10安装Mac(OSX Leopard)主题
- Linux tar 的一些使用例子
- linux tar命令详解
- 输入时整数和小数验证 带“,”区分
- New