|
1. Conectando os níveis superior e inferior Na seção anterior, falamos sobre o uso de ADCs e amostramos o sensor de temperatura no chip. Em projetos reais, o número de sensores costuma ser grande e uma grande quantidade de dados de conversão deve ser processada. Mover esses dados vai colocar muita pressão na CPU. Para liberar a CPU e dar energia para fazer outras coisas, o DMA (Acesso Direto à Memória) pode ser útil~ A introdução a seguir é um trecho do Tutorial de Prática de Tecnologia Zigbee: DMA é uma abreviação de acesso direto à memória, que é "acesso direto à memória". Este é um modo de transmissão de dados de alta velocidade no qual unidades periféricas como transceptores ADC/UART/RF e memória podem trocar dados diretamente sob o controle do "controlador DMA" sem pouca intervenção da CPU. Além de fazer um pouco de processamento no início e no fim da transferência de dados, a CPU pode realizar outros trabalhos durante a transferência. Dessa forma, a CPU e essas interações de dados estão trabalhando em paralelo na maior parte do tempo. Como resultado, a eficiência geral do sistema pode ser muito melhorada.
Como você pode ver na introdução, DMA pode ser usado em muitos cenários. Este experimento envolve apenas a transmissão mais simples de DMA e visa demonstrar o uso geral do DMA. Quanto à aplicação da DMA em outros cenários, ela será implementada em experimentos abrangentes no futuro. 2. Experimento de transmissão DMA(1) Introdução ao experimentoCaracteres do arraysourceStringO conteúdo é transferido para o array de caracteres via DMAdestString, o resultado da conversão é exibido no PC através da porta serial. (2) Fluxograma de programas
(3) Código-fonte experimental e análise/*
Descrição Experimental: O conteúdo do sourceString do array de caracteres é transferido para o array de caracteres destString via DMA, e o resultado da conversão é exibido no PC pela porta serial.
*/
#include
#define liderou1 P1_0
#define P1_1 liderado2
#define liderou 3 P1_2
#define P1_3 Led4
/*用于配置DMA的结构体
-------------------------------------------------------*/
#pragma campos de bits=invertido
typedef struct
{
sem assinatura CharSRCADDRH; //源地址高8位
sem assinatura CharSRCADDRL; //源地址低8位
sem assinatura CharDESTADDRH; //目的地址高8位
sem assinatura CharDESTADDRL; //目的地址低8位
sem assinatura CharVLEN:3; //长度域模式选择
sem assinatura CharLENH:5; //传输长度高字节
sem assinatura CharLENL:8; //传输长度低字节
sem assinatura CharTAMANHO DA PALAVRA:1; //字节(byte)或字(word)传输
sem assinatura CharTMODE:2; //传输模式选择
sem assinatura CharTRIG:5; //触发事件选择
sem assinatura CharSRCINC:2; //源地址增量:-1/0/1/2
sem assinatura CharDESTINC:2; //目的地址增量:-1/0/1/2
sem assinatura CharIRQMASK :1; //中断屏蔽
sem assinatura CharM8:1; //7或8bit传输长度,仅在字节传输模式下适用
sem assinatura CharPRIORIDADE:2; //优先级 }DMA_CFG; #pragma bitfields=padrão
/*系统时钟初始化
-------------------------------------------------------*/
vazioxtal_init(vazio)
{ SONO &= ~0x04; //都上电
enquanto(! (SONO &0x40)); //晶体振荡器开启且稳定 CLKCON &= ~0x47; Escolha um oscilador de cristal de 32MHz SONO |=0x04;
}
/*LED初始化
-------------------------------------------------------*/
vazioled_init(vazio)
{ P1SEL =0x00; P1 é a porta normal de E/S P1DIR |=0x0F; Saída P1.0 P1.1 P1.2 P1.3
liderado1 =1; //关闭所有LED liderado2 =1; Liderado3 =1; liderado4 =1;
}
/*UART0通信初始化
-------------------------------------------------------*/
vazioUart0Init(sem assinatura CharStopBits,sem assinatura CharParidade)
{ P0SEL |= 0x0C; //初始化UART0端口,设置P0.2与P0.3为外部设备IO口 PERCFG&= ~0x01; Selecione UART0 como a primeira posição opcional, ou seja, RXD para P0.2 e TXD para P0.3
U0CSR =0xC0; Coloque no modo UART e ative o aceitador
U0GCR =11; U0BAUD =216; //设置UART0波特率为115200bps
U0UCR |= StopBits| Paridade; //设置停止位与奇偶校验
}
/*UART0发送数据
-------------------------------------------------------*/
vazio Uart0Send(sem assinatura Chardados)
{
enquanto(U0CSR&0x01); //等待UART空闲时发送数据 U0DBUF = data;
}
/*UART0发送字符串
-------------------------------------------------------*/
vazioUart0SendString(sem assinatura Char*s)
{
enquanto(*s !=0) //依次发送字符串s中的每个字符 Uart0Send(*s++);
}
/*主函数
-------------------------------------------------------*/
vaziomain(vazio)
{ DMA_CFG dmaConfig; //定义配置结构体
sem assinatura CharsourceString[]="Eu sou a FonteString!"; //源字符串
sem assinatura ChardestString[Tamanhode(sourceString)] ="Eu sou o destString!"; //目的字符串
Chareu;
Charerro=0;
xtal_init(); //系统时钟初始化 led_init(); Uart0Init(0x00,0x00); //UART初始化
Uart0SendString(sourceString); //传输前的原字符数组 Uart0SendString(destString); //传输前的目的字符数组
//配置DMA结构体 dmaConfig.SRCADDRH=(sem assinatura Char)((sem assinatura int)&fonteString >>8); //源地址 dmaConfig.SRCADDRL=(sem assinatura Char)((sem assinatura int)&sourceString);
dmaConfig.DESTADDRH=(sem assinatura Char)((sem assinatura int)&destString >>8); //目的地址 dmaConfig.DESTADDRL=(sem assinatura Char)((sem assinatura int)&destString);
dmaConfig.VLEN=0x00; //选择LEN作为传送长度
dmaConfig.LENH=(sem assinatura Char)((sem assinatura int)Tamanhode(fonteString) >>8); //传输长度 dmaConfig.LENL=(sem assinatura Char)((sem assinatura int)Tamanhode(sourceString));
dmaConfig.WORDSIZE=0x00; //选择字节(byte)传送
dmaConfig.TMODE=0x01; //选择块传送(block)模式
dmaConfig.TRIG=0; Sem gatilho (pode ser entendido como acionamento manual)
dmaConfig.SRCINC=0x01; //源地址增量为1
dmaConfig.DESTINC=0x01; //目的地址增量为1
dmaConfig.IRQMASK=0; //DMA中断屏蔽
dmaConfig.M8=0x00; //选择8位长的字节来传送数据
dmaConfig.PRIORITY=0x02; //传输优先级为高
DMA0CFGH=(sem assinatura Char)((sem assinatura int)&dmaConfig >>8); //将配置结构体的首地址赋予相关SFR DMA0CFGL=(sem assinatura Char)((sem assinatura int)&dmaConfig);
DMAARM=0x01; //启用配置
DMAIRQ=0x00; //清中断标志 DMAREQ=0x01; //启动DMA传输
enquanto(! (DMAIRQ&0x01)); //等待传输结束
para(i=0; eu <Tamanhode(sourceString); i++) //校验传输的正确性 {
se(sourceString!=destString) error++; }
se(erro==0) //将结果通过串口传输到PC { Uart0SendString("Correto!"); Uart0SendString(destString); //传输后的目的字符数组 }
senão Uart0SendString("Erro!");
enquanto(1);
}
O processo básico de uso da DMA é:Configurar DMA → Habilitar configuração → Comece a transferência DMA → Espere a transferência DMA terminar.Os seguintes são, respectivamente: (1) Configurar DMA: Primeiro, a DMA deve ser configurada, mas a configuração da DMA é especial: em vez de atribuir valores diretamente a alguns SFRs, ela define uma estrutura externamente, atribui valores a ela e então atribui os 8 bits superiores do primeiro endereço dessa estruturaDMA0CFGH, dando a ele 8 dígitos inferioresDMA0CFGL。 (Para instruções detalhadas na estrutura de configuração, consulte o manual chinês CC2430) Dicas CC2430Há dois pontos a esclarecer sobre a definição de estruturas de configuração no código-fonte acima: (1) Domínio dos bits Ao definir essa struct, muitos dois-pontos (:) são usados, seguidos por um número, chamado de "campo de bits": Domínio de bits significa que a informação não precisa ocupar um byte completo quando armazenada, mas ocupa apenas alguns ou um bit binário. Por exemplo, ao armazenar uma quantidade de comutação, há apenas dois estados, 0 e 1, e você pode usar um bit binário. Para economizar espaço de armazenamento e facilitar o processamento, C fornece uma estrutura de dados chamada "campo de bits" ou "campo de bits". O chamado "campo de bits" divide os binários de um byte em várias regiões diferentes e descreve o número de bits em cada região. Cada domínio possui um nome de domínio, permitindo operações por nome de domínio no programa. Isso permite que vários objetos diferentes sejam representados em um campo binário de bytes. (2) Funções comuns abstratas Leitores atentos perceberão que atribuir um valor a uma estrutura frequentemente envolve a atribuição de um valor de tipo int sem sinal de 16 bits a dois valores de tipo de carvão não assinados de 8 bits, da seguinte forma: dmaConfig.SRCADDRH=(sem assinatura Char)((sem assinatura int)&fonteString >>8); //源地址 dmaConfig.SRCADDRL=(sem assinatura Char)((sem assinatura int)&sourceString);
Para esse tipo de função frequentemente utilizada, podemos muito bem abstraí-la como uma função geral, da seguinte forma: #define SET_WORD(destH,destL,word)
fazer{ destH=(sem assinatura Char)((sem assinatura int)palavra >>8); destL=(sem assinatura Char)((sem assinatura int)palavra); }enquanto(0)
No futuro, sempre que precisar realizar uma operação de divisão semelhante, pode chamá-la diretamente, da seguinte forma: SET_WORD(dmaConfig.SRCADDRH, dmaConfig.SRCADDRL, &sourceString);
(2) Habilitar configuração: Primeiro, o primeiro endereço da estrutura&dmaConfigOs 8 bits alto/baixo são atribuídos ao SFR, respectivamenteDMA0CFGHeDMA0CFGL(onde 0 representa a configuração do canal 0, CC2430 contém 5 canais DMA, e o canal 0 é usado aqui). SimDMAARM.0Atribua um valor de 1 para habilitar a configuração do canal 0, de modo que o canal 0 fique em modo de funcionamento. (3) Habilitar a transmissão DMA:CertoDMAREQ.0Atribua um valor 1 para iniciar a transmissão DMA do canal 0. (4) Aguardar a transmissão do DMA:Após a transmissão do DMA do canal 0, a interrupção será acionada e a bandeira de interrupção do canal 0 será acionadaDMAIRQ.0será automaticamente definido como 1. Cada caractere das duas cadeias é então comparado e o resultado da verificação é enviado ao PC. (4) Resultados experimentaisPrimeiro, abra a ferramenta de depuração de portas seriais, depois inicie a depuração do CC2430, e a seguinte tela aparecerá:
Você vai encontrardestStringO conteúdo foi completamente reveladosourceStringpreenchido. Pronto~ 3. ConclusãoEsta seção introduz o uso do DMA, embora seja muito simples, mas acho que você entendeu o uso básico do DMA e também pode analisá-lo com calma ao enfrentar seus cenários complexos de uso no futuro. Não importa o quão bom seja um desktop, ele vai travar, e da mesma forma, um sistema embarcado inevitavelmente estagna. Na próxima seção, apresentaremos um método muito eficaz de reinício sistemático: os watchdogs.
|