一步一步和我一起走,进入缤纷的嵌入式世界(连载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


这里,只贴出了核心的代码,如果有朋友感兴趣可以跟帖索要全部代码。下次我们侃侃其他方面的设计。

原创粉丝点击