假设UCOS中有3个任务,Task0,Task1,Task2(IIS任务),Task3,优先级为Task0>Task1>Task2(IIS任务)>Task3:
1.优先级最高的任务Task0的延时(OSTimeDely)或者说暂停时间要大于后边所有任务的执行时间之和?
2.OSIntEnter()和OSIntExit()的是否ucos中断时必须用,以及它们的放置位置,是否要根据自己程序的实际情况而定,不能照搬课本(如下图):(我在做这个实验时用没用,程序都能正常执行)
以下面程序为例,
a)如果把OSIntEnter()和OSIntExit()加在DMA2_IIS_End()中断服务程序中如下,中断返回时返回到while(!Tx_flag);语句处,如果在 OSIntExit(); 中发生了任务调度,切换到高优先级去执行,则while(!Tx_flag);以下的代码就无法执行,DMA2和IIS就无法关闭。
b)如果把OSIntEnter()和OSIntExit()加在void Start_IIS_DMA2(volatile unsigned char *start_addr, unsigned int play_size)程序中的前后,OSIntExit();根据任务就续表情况来切换任务,1)如果没有发生切换返回时OSTimeDly();函数也要检测就续表,根据情况来切换任务,这两个函数执行的动作不就重复了吗?
2)如果发生了任务切换,假如切换到了Task1,Task2中的OSTimeDly();就没有执行,任务Task2在就续表中还是显示已经就绪,也没有暂停延时,当Task1任务执行完时,再次发生任务调度切换,由于Task2已就绪,此时就有可能再次执行Task2,如此循环Task3就没有执行的机会,不知道OSIntEnter()和OSIntExit()是不是必须有,还是尽量不要?
void DMA2_IIS_End(void)
{
OSIntEnter()
ClearPending(BIT_DMA2); //清除中断标志位
rINTMSK &= ~(BIT_DMA2); //开中断,以等待下次中断
Tx_flag=1;
OSIntExit();
}
[localimg=118,150]1[/localimg]
3.在UCOS-II下用中断函数不要加__irq,注意函数声明和定义中都不能要。
4.还有OS_ENTER_CRITICAL()和OS_ENTER_CRITICAL(),应该放什么地方,是不是UCOS中断时也必须用到?
5.之前按网上说的方法,UCOS移植裸机DMA中断(IIS音频用到),一直不成功,要么死机要任务切换不出来,还有进入不了中断,后来莫名其妙的就好了。或者说是把IIS音频初始化,和DMA及其中断初始化都加入到ucos的while循环中,程序就好了,还有问题的根源可能在于中断服务子程序带有关键字__irq,把此关键字去掉,无论是声明中还是定义中,此方法可能应该不具有通用性,还得再测试。UCOS中断问题困扰我好多天,一直没搞明白。
//主函数中IIS任务Task3
void Task3(void *pdata)
{
int i;
// MMU_Init();
IIS_DMA2_Int_Init();
while(1)
{
Speaking_wav();//语音提示
OSTimeDly(OS_TICKS_PER_SEC);
}
}
//IIS程序
#include "config.h"
#include "WindowsXP_Wav.h"
#define L3C (1<<4) //GPB4 = L3CLOCK
#define L3D (1<<3) //GPB3 = L3DATA
#define L3M (1<<2) //GPB2 = L3MODE
#define downloadAddress ((volatile unsigned char *)0x31000000) //声音数据保存地址
//unsigned int downloadAddress=0x31000000;
void DMA2_IIS_End(void);
int Tx_flag;
//GPIO设置为IIS功能管脚
void IIS_PortSetting(void)
{
//配置L3接口总线,GPB2:L3MODE, GPB3:L3DATA, GPB4:L3CLOCK
rGPBUP = rGPBUP & ~(0x7<<2) | (0x7<<2); //GPB[4:2] 上拉电阻无效
rGPBCON = rGPBCON & ~(0x3f<<4) | (0x15<<4); //GPB[4:2] 输出
rGPBDAT = 0x1e4; //起始状态 : L3M=H, L3C=H
// I2SSDO:GPE4 I2SSDI:GPE3 CDCLK:GPE2 I2SSCLK:GPE1 I2SLRCK:GPE0
rGPEUP = rGPEUP | 0x1f; //GPE[4:0] 上拉电阻无效
rGPECON = rGPECON & ~(0x3ff) | 0x2aa; //GPE[4:0]配置为I2SSDO:I2SSDI:CDCLK:I2SSCLK:I2SLRCK
}
void WriteL3(unsigned char data, int mode)
{
int i,j;
if(mode == 1)
{
rGPBDAT = rGPBDAT&(~(L3D | L3M |L3C)) |L3C; //地址模式,根据手册L3M为LOW,L3C为high
}
else
{
rGPBDAT = rGPBDAT & (~(L3D |L3M |L3C)) | (L3M|L3C); //数据模式 L3M为高
}
delay(10); //tsu(L3) > 190ns
//传输数据
for(i=0;i<8;i++) //数据传输中L3MODE为低,8个L3CLOCK脉冲
{
if(data&0x01)
{
rGPBDAT &= ~L3C; //L3C=L
rGPBDAT |= L3D; //L3D=H
delay(10);
rGPBDAT |= L3C; //L3C=H
rGPBDAT |= L3D; //L3D=H
delay(10);
}
else
{
rGPBDAT &= ~L3C; //L3C=L
rGPBDAT &= ~L3D; //L3D=L
delay(10);
rGPBDAT |= L3C; //L3C=H
rGPBDAT &= ~L3D; //L3D=L
delay(10);
}
data>>=1;
}
rGPBDAT = rGPBDAT & ~(L3D | L3M | L3C) | (L3C | L3M); //L3M=H,L3C=H
}
//配置UDA1341
unsigned UDA1341_Init(void)
{
int sound_volume=35; //音量,数据越小音量越大
WriteL3(0x16,1);
WriteL3(0x60,0); // 0,1 ,10,000,0 复位
WriteL3(0x16,1);
WriteL3(0x10,0); //0,0,01, 000,0 : 状态0, 384fs,IIS,no DC-filtering
WriteL3(0x16,1);
WriteL3(0xc1,0); //1,0,0,0, 0,0,01:状态1,
//Gain of DAC 6 dB,Gain of ADC 0dB,ADC non-inverting,
//DAC non-inverting,Single speed playback,ADC-Off DAC-On
WriteL3(0x14,1 ); //DATA0 (000101xx+00)
WriteL3(sound_volume,0); //1,0,0,0, 0,0,01 ,音量调节 数据越小音量越大
}
//开启IIS
void Start_IIS_DMA2(volatile unsigned char *start_addr, unsigned int play_size)
{
// OSIntEnter();
Tx_flag=0;
//初始化DMA通道2
rDMASKTRIG2 = (1<<2)|(0<<1); //关DMA通道2
rDISRC2 = (int)(start_addr); //源数据起始地址
rDISRCC2 = (0<<1) | (0<<0); //AHB系统总线,数据传送后源地址增加
rDIDST2 = ((unsigned int)IISFIFO); //发送FIFO地址,目标地址
rDIDSTC2 = (0<<2) | (1<<1) | (1<<0);//TC为0中断出现 ,APB外设总线,每次传输后地址不变
rDCON2 = (1<<31)+(0<<30)+(1<<29)+(0<<28)+(0<<27)+(0<<24)+(1<<23)+(0<<22)+(1<<20)+(play_size/2);
rDMASKTRIG2 = (0<<2) | (1<<1) | (0<<0); // DMA2通道打开
//初始化IIS,开始发送
rIISCON = (1<<5) | (0<<4) | (1<<2) | (1<<1); //发送DMA请求使能,接收DMA请求禁止,IIS预分频器使能
rIISPSR = 3<<5|3; //预分频A=3,B=3
//PCLK为时钟源,输出模式,IIS模式,每个声道16位,CODECLK=384fs,SCLK=32fs
rIISMOD = (0<<9)|(0<<8) | (2<<6) | (0<<5) | (0<<4) | (1<<3) | (1<<2) | (1<<0);
rIISFCON = (1<<15) | (1<<13); //发送FIFO为DMA模式,发送FIFO使能
rIISCON |= 0x1; //启动IIS
delay(1000);
while(!Tx_flag){delay(100);}//此处要有延时,否则中断返回时,Tx_flag=1也不会跳过while往下执行
Tx_flag=0;
//IIS Tx Stop
delay(10);
rIISCON &= ~(1<<0); //IIS Interface stop
rDMASKTRIG2 = (1<<2); //DMA2停止
rIISFCON = 0x0; //发送/接收 FIFO 禁止
}
//DMA2中断初始化
void IIS_DMA2_Int_Init(void)
{
rPRIORITY = 0x00000000; // 使用默认的固定的优先级
rINTMOD = 0x00000000; // 所有中断均为IRQ中断
rINTPND |= BIT_DMA2 ; // clear pending bit
rSRCPND |= BIT_DMA2 ;
rINTMSK |= (BIT_DMA2); //关中断
pISR_DMA2 = (unsigned)DMA2_IIS_End; //注册向量表
rINTMSK &= ~(BIT_DMA2); //开中断
}
//执行IIS
void Speaking_wav(void)
{
volatile unsigned char *sound_buf=downloadAddress;//声音数据存放首地址给sound_buf
// unsigned char *sound_buf;
unsigned int i;
unsigned int downloadSize = 243552;
// sound_buf = (unsigned char *)downloadAddress ;
for( i = 0; i < 243552; i++ ) sound_buf = WindowsXP_Wav ;
IIS_PortSetting();
UDA1341_Init();
Start_IIS_DMA2(sound_buf,downloadSize);
}
//中断服务程序
void DMA2_IIS_End(void)
{
ClearPending(BIT_DMA2); //清除中断标志位
rINTMSK &= ~(BIT_DMA2); //开中断,以等待下次中断
Tx_flag=1;
} |