curso dsp tms320_c24
Post on 30-Jul-2015
124 Views
Preview:
TRANSCRIPT
CEFET-PR
TMS320C24x DSP DESIGN
GUIA DO ESTUDANTE
Outubro 2002 Treinamento Técnico
Esta apostila foi desenvolvida por Alexandre Kremer, sob a orientação do prof.
Luciano Scandelari, durante a realização de estágio supervisionado.
Para se desenvolver o conteúdo deste material foram consultados os manuais de
referência técnica do processador e do kit de desenvolvimento, além de diversas pesquisas
realizadas nos sites da Texas Instruments, bem como apostilas de workshop realizados por
outras entidades.
ii
1. POR QUE USAR DSP?
• Arquitetura otimizada • Conjunto de instruções elaboradas para processamento de sinais; • Arquitetura minimiza problemas numéricos em processamento discreto de sinais.
• Alta performance • Implementação de algoritmos complexos em tempo real; • Implementação de altas taxas de amostragem; • Minimiza atrasos computacionais; • Performance para implementar funções múltiplas.
• Benefícios do sistema digital • Flexibilidade e certa facilidade em se realizar upgrades; • Possibilidade de se realizar "time sharing"; • Está livre dos efeitos ambientais como temperatura; • Largura de banda e resolução próxima dos sistemas analógicos.
A tabela a seguir apresenta algumas funções que o DSP pode realizar com facilidade e os benefícios principais que a utilização do mesmo pode trazer.
abela 1 - Possibilidades de Implementações
Função do DSP Benefícios
Algoritmos de filtros Notch Cancela ressonância mecânica
Algoritmos de filtros adaptativos Kalman Reduz ruído dos sensores
Algoritmos estimados de estados Estima múltiplas variáveis (velocidade/posição)
Algoritmos de controle vetorial Transformação dos eixos em tempo real
Modulação por largura de pulso Controle digital de inversores (motor, no break)
Algoritmo de controle PID de alta ordem Controle preciso
Altas taxas de amostragem Largura de banda elevada
Multiplexação no tempo Permite várias implementações com 1 DSP
Algoritmos de controle Fuzzy Controle inteligente
Controlador de tempo morto Chaveamento seguro e rápido
Controlador de estados Controle de muitas variáveis
Correção do fator de potência Reduz perda de potência
Algoritmos FFT Implementa análise espectral
1
2. TECNOLOGIA UTILIZADA
Com o advento do processador digital de sinais, um processador matemático, viu-se
que as funções de controle poderiam ser facilmente implementadas além do fato de que as
demais funções periféricas poderiam continuar sendo incorporadas pelo DSP. A limitação do
hardware estava superada e o objetivo primário dependeria apenas de uma adaptação do
sistema ao mesmo. As informações descritas no decorrer desta parte são importantes para se
compreender o motivo da utilização deste dispositivo no nosso processo, bem como nos
familiarizar à uma "nova" tecnologia que possui muito a oferecer.
O TMS320F243 é um processador digital de 16 bits que opera a uma freqüência de 20
M Hz. Construído com a arquitetura Harvard modificada, onde temos barramentos de
programa e de dados de forma independente, o processador permite acesso simultâneo a
instruções de programa e dados, dobrando o fluxo de informações para aplicações
matemáticas. Este processador possui um arranjo interno extremamente interessante e
eficiente. Dentre as melhorias podemos citar:
• Capacidade de se inicializar a memória de dados a partir da memória de
programa;
• Capacidade de se transferir a memória de dados para memória de programas
(bit CNF).
Estas características permitem se multiplexar a memória entre aplicações bem como se
inicializar a memória de dados com constantes, eliminando-se a necessidade de uma ROM de
dados.
Esta família em especial (família 2000) é voltada às aplicações de controle digital,
onde temos dois timers independentes que podem controlar até 8 saídas PWM onde duas
2
delas são independentes e as outras seis poderão ser utilizadas para controle vetorial ou
controle simples, onde três são independentes e as outras três são seus complementos.
2.1. CARACTERÍSTICAS DO TMS320F243
É necessário inicialmente se efetuar um estudo detalhado das características do
processador que será utilizado, para se ter então a convicção de que este processador
realmente atenderá as expectativas de operação e, principalmente, se alguma limitação
poderia vir à tona em etapas futuras. Foram analisados diversos documentos relativos não
somente ao processador em si, mas também a algumas aplicações de processos e
metodologias relevantes ao nosso caso. Muitas destas informações puderam ser encontradas
no site da Texas Instruments http://www.ti.com/ onde constam vários documentos válidos nos
conhecidos Application Notes.
Algumas características do processador utilizado são:
• Tecnologia CMOS de alta performance;
• Possui o CoreCPU T320C2xx que é compatível com TMS320C2xx
• Sua memória está organizada como:
- RAM de acesso duplo para programa e dados de 544 palavras
x 16 bits localizada on-Chip (DARAM);
- Uma Flash EEPROM de 8K palavras x 16 bits;
- Possui 224K palavras x 16 bits de endereçamento total
atingível.
• Interface para memória externa;
• Possui o Módulo Gerenciador de Eventos (EVM) que consistem em:
3
- 8 canais comparadores/PWM's ;
- 2 Timers de 16 bits com seis modos de operação, incluindo
contagem Up e Up/Down;
- 3 unidades Full Compares com capacidade de programação de
Deadband (Tempo morto);
- 3 unidades de captura;
• Conversor A/D único com 8 canais multiplexados de entrada;
• Módulo CAN (Controller Area Network);
• 26 pinos de I/O os quais são programáveis de forma individual;
• 6 pinos dedicados de I/O;
• Watchdog Timer;
• Interface serial de comunicação;
• Módulo de Interface Serial de 16 bits para periféricos;
• 5 tipos de interrupção externa das quais duas podem ser mascaráveis;
• 3 modos de queda de energia para operação em baixo consumo;
• Encapsulamento tipo QFP PGE de 144 pinos.
Como descrito anteriormente, o DSP possui espaços de endereçamento de memória
separados, podendo ser de programa, dados ou I/O. Isto permite que acessos simultâneos
sejam feitos em barramentos diferentes, o que otimiza ainda mais a utilização dos recursos
deste processador.
4
2.1.1. A CPU
A Unidade de Processamento Central (CPU) incorpora o multiplicador e a Unidade de
Lógica Aritmética Central (CALU) além de três deslocadores (shifters) e vários registradores
de controle. A figura 1 ilustra a CPU sem os registradores de controle.
Figura 1 - Unidade de Processamento Central
2.1.2. O Multiplicador
O hardware do multiplicador foi desenhado para realizar uma multiplicação em um
único ciclo de máquina. Como ilustrado na figura 1, uma das entradas é proveniente do
registrador temporário (T) e a outra vem do barramento de dados ou de programa. O
resultado é fornecido em 32 bits e armazenado no registrador de produto (P) que estará
disponível à CALU.
5
2.1.3. A CALU
Esta unidade contém a ALU (Unidade de Lógica Aritmética) e três shifters separados.
A ALU possibilita a realização de operações aritméticas em um único ciclo de máquina. O
resultado estará disponível em 32 bits no Acumulador (ACC).
O C24x possui um shifter para pré-ajuste do tamanho da informação provenientes do
barramento de dados para a ALU, um shifter para pós-ajuste do acumulador para o
barramento de dados e um shifter para se escalonar os resultados provenientes do
multiplicador. Qualquer instrução que envolva a ALU será executada da seguinte forma:
1. O dado é lido da RAM a partir do barramento de dados;
2. O dado passa pelo shifter e em seguida para a ALU onde a instrução será
realmente executada;
3. O resultado se encontrará no acumulador.
Uma entrada para a ALU sempre será provida pelo acumulador (ACC). A outra
poderá ser proveniente do registrador de produto (P), ou diretamente da memória de dados.
2.1.4. O Mapa de Memória
O C24x possui um espaço de memória dividido em três regiões:
- 64 K de programa;
- 64 K de dados;
- 64 K para I/O
Possuindo um mínimo de 544 palavras de RAM on-chip, a qual é, às vezes, referida
como RAM de acesso duplo. No reset, esta memória se encontra na área de dados, mas uma
porção desta pode ser realocada para a área de programa, via software.
6
A segunda memória on-chip é ROM, a qual está localizada no início da área de
programa. Esta poderá ser usada ou ignorada através do controle (MP/MC). A quantidade de
memória on-chip não volátil (ROM ou Flash) varia dentro da família dos dispositivos C24x.
2.1.5. Pipeline
O C24x possui um "pipeline" de instruções o qual resulta em uma maior eficiência na
execução do programa. As fases do pipeline são fetch - decode - read - execute e são
independentes uma da outra. A figura 2 apresenta a estrutura do pipeline.
Figura 2 - O Pipeline
7
3. MODOS DE ENDEREÇAMENTO
Esta seção descreve os tipos de endereçamento disponíveis no C24x. A habilidade de
se expressar constantes, especialmente em inicializações, é chamada de endereçamento
imediato. Endereçamento direto permite acesso geral da memória. Endereçamento indireto faz
uso dos registradores auxiliares para fornecer suporte de ponteiro para várias funções.
Conforme mencionado anteriormente, existem tr6es faixas de 64 K de memória para
programa, dados e I/O. Uma faixa de 64 K requer um endereço mínimo de 16 bits para que se
possa identificar cada posição unicamente. O conteúdo de cada posição será tratado como
"palavra de 16 bits".
A RAM de dados é composta de dois blocos de memória localizados em 0060h -
007Fh e 0200h - 03FFh no mapa de dados. Todos os dispositivos baseados no C24x possuem
estas características em comum. O bloco de acesso duplo chamado de DARAM B0, está
localizado na posição 0200h - 02FFh na memória de dados no reset, mas pode ser transferida
para a posição FF00h - FFFFh na memória de programa via bit CNF sobre o controle de
programa. A figura 3 ilustra a organização de memória.
Figura 3 - Mapa de Memória do Processador
8
3.1. ENDEREÇAMENTO IMEDIATO (CONSTANTES)
No endereçamento imediato, o operando é parte da palavra de instrução e é
identificado pelo caracter " # ".
Valores pequenos podem ser declarados com uma única palavra , ao passo que valores
grandes requerem uma segunda palavra de programa ( e mais de um ciclo para ser executada).
Valores imediatos curtos são geralmente limitados a 8 bits, mas dependendo da instrução na
qual eles serão usados, estes podem variar desde um único bit até 13 bits. Palavras que
excedem o limite de uma constante curta tornam-se duas palavras, como é mostrado a seguir:
ADD #12h ; 0012h é adicionado ao ACC, com 1 ciclo
ADD #3456h ; 3456h é adicionado ao ACC, com 2 ciclos
Instruções com imediatos longos permitem também um segundo operando a ser
especificado: um valor de deslocamento o qual pode ser usado para escalonar uma constante
de 16 bits em um registro de 32 bits. Para explicações completas da lista de operações que
suportam endereçamento imediato veja a bibliografia TMS320C24x User's Guide.
3.2. ENDEREÇAMENTO DIRETO (ACESSO E DEFINIÇÕES DE VARIÁVEIS)
Uma vez que o C24x possui palavras de 16 bits e uma largura de endereçamento de 16
bits também, tudo leva a crer que o uso da memória necessita de dois ciclos por instrução, isto
é, um para especificar uma operação, e o segundo para expressar o endereço da memória de
dados a ser acessado. No entanto, isto tornaria o acesso por endereçamento direto muito lento,
o que seria indesejável na maioria dos sistemas. Ao invés disto, o C24x permite ao usuário
especificar uma área de memória, e instruções endereçadas diretamente operam com esta
9
faixa reduzida de memória. Esta memória '"paginada" é comum a muitos processadores e
possibilita estabelecer um compromisso entre faixas de memória e velocidade.
No C24x, um Data Page (DP) de 9 bits é estabelecido para se identificar qual parte da
memória estará atingível. Então, a cada DP, 128 posições poderão ser acessadas diretamente,
onde o número total de páginas é 512. Estas 128 posições podem ser acessadas com somente
7 bits, tornando possível o acesso com um único ciclo. Desde que o DP é um registrador
programável, o mapa de memória estará acessível em blocos de 128 posições para cada DP. A
figura 4 ilustra o esquema de paginação e a figura 5 a formação de endereços.
10
Figura 4 - Paginação da Memória de Dados
Figura 5 - Formação de Endereço Direto Válido
O endereçamento direto geralmente se inicia com a inicialização do DP, mais
comumente através da instrução LDP (Load Data Page). Qualquer número de operações
podem ser postadas na página selecionada.
Diversas precauções devem ser tomadas pelo usuário para se utilizar o endereçamento
direto. Uma delas é sempre utilizar o "#" na instrução LDP pois este símbolo indica um valor
numérico, ao passo que a ausência deste símbolo especifica uma posição de memória. A
segunda delas é a definição das fronteiras de páginas. Realmente não se sabe quando estas
fronteiras serão cruzadas e a referente variável poderia estar então em outra página que não a
especificada em linhas anteriores de programa. Existem alguns métodos para se evitar que
11
isto aconteça, mas como o kit de testes possui algumas limitações , alguns destes métodos não
puderam ser desenvolvidos na prática, mas o método mais seguro é o de se estabelecer o DP
em cada instrução que necessite a mudança da página corrente.
Figura 6 - Exemplo de Endereçamento Direto
3.3. ENDEREÇAMENTO INDIRETO (INDEXAÇÃO E TABELAS)
O endereçamento indireto é um método poderoso e eficiente para se acessar dados
armazenados em listas, arrays ou qualquer outro tipo de grupos ordenados de dados. Ao
contrário do endereçamento direto, o endereço não é explicitado na palavra de instrução, mas
sim em um registrador auxiliar (ARx). A utilização de um AR fornece uma série de
benefícios. Inicialmente, os AR's possibilitam apontar para qualquer posição de memória sem
a necessidade do DP, pois estes são registradores de 16 bits. Outra vantagem é o fato de que
os registradores auxiliares podem ser incrementados ou decrementados automaticamente após
a leitura de um operando durante uma mesma instrução, o que possibilita tornar os processos
iterativos rápidos e fáceis.
Ao todo, oito AR's estão disponíveis nos C24x. Para que se possa usar o
endereçamento indireto, é necessário primeiro se inicializar e selecionar um AR. Para se
inicializar um AR utiliza-se a instrução LAR (Load Auxiliar Register) e para se selecionar um
registrador auxiliar utiliza-se a instrução MAR (Modify Auxiliar Register).
3.3.1. Operandos do Endereçamento Indireto
A utilização do " * " indica o operador indireto, definindo o uso do AR corrente como
ponteiro para o valor a ser utilizado. Quando o sinal de soma " + " for adicionado à instrução,
isto representa o auto incremento do registrador, onde o valor do registrador corrente é
12
incrementado de um logo após a leitura do operando. Isto acontece de forma análoga para o
sinal de menos " - " que especifica o auto decremento. Como no C24x existem hardwares
dedicados à implementação de auto decremento ou incremento, nenhum ciclo extra será
exigido para estas operações.
O endereçamento indireto permite que se usem registradores de 16 bits como
ponteiros para memória de dados. Isto é freqüentemente usado para se operar com arrays de
dados. A tabela a seguir ilustra as possibilidades de operandos do endereçamento indireto:
Tabela 2 - Operandos para o Endereçamento Indireto
Opção Função * Indica o AR corrente sem modificação
*+ Incrementa o AR corrente *- Decrementa o AR corrente
*0+ Adiciona valor de AR0 ao AR corrente *0- Subtrai o valor de AR0 do AR corrente
*BR0+ Adiciona AR0 ao AR corrente com propagação reversa de carry *BR0- Subtrai AR0 do AR corrente com propagação reversa de carry Exemplo de instrução :
ADD *+ , 1 , AR0
1. *+ utiliza AR corrente incrementando-o;
2. 1 especifica o deslocamento para a esquerda de 1 bit (0 é o padrão);
13
3. AR0 Novo ARP (modifica o registrador corrente para AR0)
Figura 7 - Indexação através dos Registradores Auxiliares Contudo, às vezes se faz necessária uma indexação com um passo diferente de 1.
Conforme indicado na tabela acima, podemos utilizar o AR0 como um registrador de uso
exclusivo para armazenar o passo da nossa indexação.
Para fins de análise de funcionamento, muitas vezes se faz necessária a visualização
do DP e dos AR's. No ambiente de debugger chamado de Code Explorer existe a
possibilidade de se visualizar o conteúdo de todos estes registradores, assim como muitas
posições de memória.
14
4. TÉCNICAS BÁSICAS DE PROGRAMAÇÃO
Esta seção apresenta três tópicos: controle de programa, operações da ALU e o uso do
multiplicador. O controle de programa oferece uma variedade de branches e instruções de
chamada de subrotinas, com várias condicionais associadas. Detalhes da ALU serão
examinados, incluindo capacidades aritméticas de 32 bits.
4.1. O CONTROLE DE PROGRAMA
O C24x fornece vários métodos de controle do fluxo de execução do programa. O
fluxo normal do mesmo se dá de forma seqüencial, isto é, o processador faz do fetch ao
execute da próxima instrução da memória de programa. Quando se fizer necessária uma
quebra desta seqüência, pode-se utilizar branches, call, traps ou interrupções soft. Os
branches transferem o controle para qualquer posição da memória de programa. As calls
também o fazem, mas permitem um fácil retorno ao ponto original da seqüência de programa
com o uso da instrução RET. As traps e interrupções soft são formas especiais de calls.
Figura 8 - Instruções de Controle de Programa
15
Os branches e calls podem ser tanto incondicionais (sempre realizadas) ou
condicionais, onde o pulo depende de estados do processador. A figura 8 ilustra as instruções
que podem ser realizadas e as condições que podem ser testadas.
4.2. OS BRANCHES
Estes tipos de instruções permitem transferência do controle para qualquer posição da
memória de programa. Muitas destas instruções são de comprimento de duas palavras, o que
acarreta na sua execução em quatro ciclos de máquina.
4.2.1. Branch Incondicional
Neste caso a instrução sempre será tomada quando aparecer. Além de modificar o PC
(Program Counter), existe também a possibilidade de se modificar o AR corrente e o ARP,
através da ARAU. A instrução pode ser escrita como:
[label] B pma [, {ind} [, next ARP] ]
onde: 0000h < pma < 0FFFFh e 0 < next ARP < 7
A primeira palavra da instrução é o opcode do branch. A segunda palavra é o
endereço da memória de programa (pma). Quando um branch normal é decodificado,
qualquer operação da ARAU especificada pelo endereçamento indireto é realizada. Quando a
instrução é executada, o PC é carregado com o pma e a execução do programa continua neste
novo endereço.
16
4.2.2. Branch Condicional
Estes saltos podem ser realizados mediante estabelecimento de condições baseadas
nos estados do processador. Sua representação é a seguinte:
[label] BCND pma, [cond 1] [,cond 2] [,…..]
Se todas estas condições forem satisfeitas, o PC será carregado com o referente pma,
senão, o PC continuará da próxima posição após o branch. Para serem executadas, elas levam
quatro ciclos de máquina. No caso de não serem tomadas devido ao não cumprimento de uma
das condições, a instrução ainda leva dois ciclos de máquina.
4.2.3. Branch Dinâmico
A instrução BACC é composta de uma única palavra a qual carrega o PC com os 16
bits inferiores do acumulador. Esta instrução fornece a capacidade de endereços programáveis
por tempo de execução e faz parte das técnicas mais avançadas de programação.
4.2.4. Branch com Decremento
A instrução BANZ constitui um caso especial dos branches condicionais. É
amplamente utilizado para se definir loops que serão realizados um certo número de vezes. É
codificado como:
[label] BANZ pma [, {ind} [, next ARP] ]
17
Esta instrução é condicional no sentido de que ela será tomada somente se o conteúdo
do AR corrente for maior que zero. Esta verificação é realizada antes de se decodificar a
instrução. Quando a instrução é tomada, automaticamente o conteúdo do AR corrente é
decrementado. Quando este valor chegar a zero, o PC passa a ser carregado com a próxima
instrução logo após esta. O AR corrente e o ARP podem ser modificados como se apresentou.
Se nenhuma modificação é especificada, o decremento do AR será de um. Quando a instrução
BANZ for utilizada ao final de um loop, N + 1 iterações do loop serão executadas se o
registrador auxiliar foi inicializado com N fora do mesmo. A figura 9 ilustra um código que
realiza um somatório de forma otimizada.
Figura 9 - Estrutura de Loop utilizando a instrução BANZ
4.3. SUBROTINAS
Uma subrotina difere de um branch no sentido de que a sua chamada é apenas um
abandono temporário da execução seqüencial do programa. Para isto, quando uma chamada é
executada, um endereço de retorno é salvo no qual o programa poderá finalizar sua execução
depois de se completar a subrotina. Quando qualquer das instruções de chamada forem
executadas, o endereço da próxima instrução será armazenado na pilha interna.
18
4.3.1. Chamando uma Subrotina
Isto é facilmente realizável através da instrução call. Como no branch incondicional,
além de modificar o PC, esta instrução pode modificar também o AR corrente e o ARP via
ARAU. Sua codificação é:
[label] CALL pma [, {ind} [, next ARP] ]
O endereço da instrução a ser executada em seguida a subrotina é armazenada na
pilha. A pilha do C24x é uma pilha de oito níveis, a qual é usada para salvar somente
endereços de retorno. Ela é compartilhada pelas chamadas e pelas interrupções. Para
aplicações que possam vir a estourar esta pilha, se faz necessário salvá-la como contexto na
memória de dados.
4.3.2. Chamadas Condicionais
Como os branches, as chamadas podem ser condicionais, e se apresentam como:
[label] CC pma, [cond 1] [, cond 2] [,……..]
Chamadas condicionais operam da mesma forma que o BCND. Para esta instrução ser
tomada, se faz necessário que todas as condições sejam satisfeitas.
19
4.3.3. Chamadas Dinâmicas
A instrução CALA permite a chamada para um pma contido no acumulador. Na sua
execução, o endereço de retorno é salvo na pilha e os 16 bits inferiores do acumulador são
carregados no PC.
4.3.4. Retorno da Subrotina
Para se retornar de uma subrotina, se faz obrigatória a utilização de instruções
específicas de retorno. Estas instruções podem ser incondicionais ou condicionais. A
instrução RET é um exemplo do primeiro caso. Sua utilização encerra a subrotina habilitando
o PC a ser carregado com o endereço salvo anteriormente na pilha. Já a instrução RETC
constitui um retorno condicional, podendo ser constituído de várias condições. É importante
lembrar que todas as condições devem ser satisfeitas para se retornar da subrotina.
4.4. UNIDADE CENTRAL DE LÓGICA ARITMÉTICA (CALU)
É onde os valores provenientes da memória de dados e/ou programa são manipulados
aritmeticamente. Os registradores e os componentes funcionais da CALU operam em
conjunto para permitir uma rápida implementação de processos matemáticos.
4.4.1. Unidade de Lógica Aritmética
A unidade de lógica aritmética é um bloco funcional o qual realiza adições, subtrações
e funções booleanas. Os resultados da ALU aparecem no registrador acumulador (ACC). Suas
entradas são provenientes do ACC (obrigatório) e da memória (dados ou programa) ou um
registrador (Produto). A 32-bit ALU e o acumulador operam com valores sinalizados ou não
20
sinalizados de até 32 bits em um único ciclo de máquina. A seguir estão alguns exemplos de
instruções que utilizam a ALU.
LACC #123 ; ACC = 123 decimal depois da instrução ; valor antigo é perdido ADD X ; ACC = 123 + conteúdo da dma "X" SUB * ; ACC = 123 + @X - conteúdo da dma apontada ; pelo AR corrente
Todos os três modos de endereçamento mostrados anteriormente podem ser utilizados
em qualquer destas instruções. Ao contrário da maioria das instruções que utilizam
endereçamento imediato, LACC #const sempre utiliza duas palavras (por isso dois
ciclos) não importando o tamanho da constante. Por exemplo:
LACC #2 ; duas palavras, dois ciclos
LACC #472Ah ; duas palavras, dois ciclos
Para casos onde se manipulam constantes de 8 bits ou menos, é aconselhável utilizar a
instrução LACL:
LACL #2 ; uma palavra, um ciclo
Esta instrução carrega o ACC inferior com o valor desejado e zera a parte alta, porém
não permite se efetuar um deslocamento de bits na mesma instrução, já a LACC permite.
Outro fato importante é que não podemos manipular números sinalizados com esta instrução
(LACL) pois esta não suporta o modo de sinal.
Outra instrução bastante utilizada no C24x é a SPLK(Store Parallel Long Immediate)
a qual armazena um valor imediato de até 16 bits em qualquer posição de memória válida.
Considere o seguinte exemplo:
LACC # valor
21
SACL memo
Este processo carrega o acumulador com um valor de 16 bits e transfere para a posição
"memo", ocupando três ciclos para ser executada. Utilizando-se:
SPLK #valor, memo
Obtemos o mesmo resultado utilizando apenas dois ciclos do processador. Porém se o
valor a ser armazenado for de 8 bits ou menos, não existe vantagem em se usar a SPLK ou
LACL/SACL.
Quando um cálculo é completado, sempre deseja-se salvá-lo em uma posição de
memória. Dependendo do cálculo, o resultado pode ser apresentado em 32 bits, e para isto
existem as instruções SACH e SACL, as quais realizam a armazenagem da parte alta (High) e
da parte baixa (Low) do acumulador respectivamente. Estas instruções podem utilizar o
endereçamento indireto. Outra característica bastante utilizada é a possibilidade de se extrair
quaisquer 16 bits contínuos do acumulador através da manipulação dos bits pelos
deslocadores (shifters), que constituem um segundo operando para a instrução
4.4.2. O Multiplicador
Tradicionalmente, a multiplicação sempre necessitava de muitos ciclos de instruções
para serem implementadas em um microprocessador, diminuindo-se a taxa na qual um
algoritmo de multiplicação intensiva seria resolvido. Isto é realmente uma veradade quando
falamos em sistemas baseados em DSP (Digital Signal Processing), os quais são compostos
por soma de produtos. Uma das características do C24x é a existência de um hardware
dedicado para realizar as multiplicações em um único ciclo.
Este multiplicador é alimentado com dois valores de 16 bits, produzindo assim sempre
um resultado de 32 bits, o qual é disponibilizado em um registrador especial chamado de
22
23
Product register (P). O resultado deve ser passado ao acumulador via barramento de 32 bits
antes de se realizar outra multiplicação. Neste processo de se acumular os produtos, um shift
pode ser pré-selecionado.
4.4.3. Utilização Básica do Multiplicador
Conforme indicado, dois valores devem ser passados ao multiplicador. No caso mais
simples, o primeiro operando é passado para o Registrador Temporário (T ou TR ou TREG)
usando-se a instrução Load Temporary (LT). O segundo operando é especificado pela
instrução de multiplicação (MPY), podendo ser dos três modos de endereçamento. Realizado
o cálculo, o resultado será de 32 bits e estará disponível no Registrador de Produto (P ou PR
ou PREG). É importante perceber que, como ambas as entradas são de 16 bits, não existem
opções de deslocamento de bits via estas instruções.
Multiplicações subseqüentes sobrescrevem produtos anteriores, sendo necessário
armazenar-se o resultado fora de P antes que este seja novamente utilizado. Muito
freqüentemente este produto faz parte de um cálculo de "soma de produtos", e isto pode ser
facilmente implementado no DSP.
PAC ; ACC = P
APAC ; ACC = ACC + P
SPAC ; ACC = ACC - P
Cada uma das instruções acima operam em 32 bits com ciclo único utilizando o
caminho dedicado entre P e o ACC. A figura 10 apresenta uma soma de produtos.
Figura 10 - Soma de Produtos
4.4.4. Uso Otimizado do Multiplicador
Conforme explicado, geralmente os algoritmos de soma de produtos possuem uma
indicação de performance pela velocidade de operação. No exemplo anterior, cada produto-
acúmulo necessitava de três instruções. Como o DSP é muito mais rápido que os
processadores padrão, é desejável que operações sejam realizadas mais rapidamente para se
implementar aplicações cada vez mais pesadas. Isto tornou-se possível pela convergência das
instruções APAC e LT na instrução LTA (Load Temporary and Accumulate). A seguir estão
apresentadas três versões:
LTP x ;ACC = P, T = conteúdo da posição x
LTA * ;ACC = ACC + P, T = valor apontado ; pelo AR corrente ou "*AR(ARP)" LTS *-,AR3 ; ACC = ACC - P, T = *AR(ARP), ; decrementa AR(ARP), ARP = 3
É importante visualizar que a carga do n-ésimo termo é realizada em paralelo com o
acúmulo do termo anterior (n-1)-ésimo. A figura 11 apresenta a mesma soma de produtos
realizada com a instrução LTA.
24
Figura 11 - Soma de Produtos com a instrução LTA
25
5. TÉCNICAS AVANÇADAS DE PROGRAMAÇÃO
Nesta seção estão algumas técnicas para se melhorar a velocidade de execução das
várias operações consideradas. Em adição, alguns destes métodos reduzem os recursos
necessários ao sistema, reduzindo o seu custo de implementação. Estas melhorias
correspondem à instrução repeat (RPT), multiply and accumulate (MAC) e operações de
movimentação de blocos.
5.1. OPERAÇÕES DE REPETIÇÃO
A instrução RPT é utilizada para direcionar o C24x a repetir a instrução seguinte um
certo número de vezes conforme especificado pelo seu operando. Esta instrução possui as
seguintes características.
• Um ciclo
• Carrega o RPTC (contador) com valores de 8 ou 16 bits
• Instrução seguinte é realizada RPTC + 1 vezes
• Sem overhead em instrução única
• Valor de repetição geralmente especificado por operando de 8 bits
• Valor de repetição pode também ser especificado direta ou indiretamente
• Os loops não podem ser interrompidos
RPT #n ; repete a próxima instrução n+1 vezes
Uma versão um pouco menos utilizada que permite utilizar um valor de contagem
proveniente da memória de dados é:
26
RPT dma ; repete @ (dma) + 1 vezes, mas só usa os 8 LSB's
A instrução RPT é quase um código rápido linear, utilizando muito menos espaço de
programa para longos procedimentos. Por exemplo, o código a seguir realiza a soma de todos
os valores de uma seqüência de 200 posições de memória de dados:
RPT #199 ; repete 200 vezes
ADD *+ ; adiciona do * e incrementa o AR corrente
A utilização desta instrução aliada a outras instruções pode tornar a execução de um
procedimento muito mais rápida que uma implementação linear. Estas instruções são:
TBLR BLDD MAC OUT SQRA SUBC
TBLW BLPD MACD IN SQRS
Figura 12 - O RPT no Endereçamento Indireto
As instruções seguintes não poderão ser utilizadas com a instrução RPT. Se utilizadas,
poderão levar o processo a estados indesejados:
• Todas as operações de branches e chamadas de subrotinas
• Todas as instruções imediatas
• Todas as instruções de repetição
• IDLE, TRAP, RET, ZAC, SPM
27
A figura 12 ilustra a utilização da instrução RPT com endereçamento indireto e a
figura 13 ilustra a utilização do RPT na indexação de passo.
Figura 13 - O RPT na Indexação
5.2. USO AVANÇADO DO MULTIPLICADOR
Desde que somas de produtos são freqüentemente encontradas em processamento
digital de sinais, é profundamente desejável que se possa implementar a multiplicação e o
acúmulo no menor intervalo de tempo possível. Vimos em seções anteriores que é possível se
realizar estas operações em dois ou três ciclos. Uma melhor performance pode ser obtida se
pudermos fazer isto em apenas um único ciclo.
Considerando-se que, em um único ciclo, dois operandos devem ser lidos e roteados
ao multiplicador, um produto deve ser realizado e um acúmulo também. A instrução LTA
realiza muitas destas funções. Ela acumula um produto e lê um operando da memória de
dados. Então, tudo que resta é a leitura de um segundo operando e roteá-lo ao multiplicador.
Infelizmente, a leitura do primeiro operando utiliza o bus de dados. Como sabemos, podemos
efetuar o acesso simultâneo ao bus de programa e dados, e por isso podemos retirar o segundo
28
operando da memória de programa, desde que este resida na mesma. Além do mais, a única
forma de selecionar uma posição na memória de programa é via contador de programa (PC).
Como resultado, operações normais da área de programa, como o fetch das instruções, deve
ser temporariamente suspenso. Estas operações são realizadas pela instrução MAC, que
requer três ciclos.
Esta instrução pode aproximar uma execução de ciclo único quando aliada à instrução
RPT. No loop de repetição, o compartilhamento do PC entre o operando e a captura das
instruções é evitado. Isto ocorre porque as instruções que são repetidas são capturadas uma
única vez e são armazenadas no registrador de instruções sendo então iteradas. Com isso, a
primeira instrução MAC requer três ciclos, porém as subseqüentes com o loop de repetição
necessitam apenas de um ciclo.
Figura 14 - Soma de Produtos com a instrução MAC
Com isso, muitas vezes podemos assumir que a utilização do MAC sempre será mais
rápida que a LTA e MPY. No entanto, quando poucos taps são calculados, a complexidade e
a sobrecarga na definição da operação MAC tornam preferível a utilização da LTA/MPY.
Aconselha-se a utilizar a instrução MAC a partir de 10 taps. A figura 14 ilustra a utilização da
instrução MAC com a RPT.
29
5.2.1. Outras Operações de Multiplicação.
Várias outras instruções utilizam a estrutura do multiplicador. Um grupo fornece a
habilidade de realizar uma função "quadrado e acúmulo". Nesta função, um único operando é
especificado e colocado em ambas as entradas do multiplicador. O resultado estará no
registrador P e o resultado anterior é somado ao acumulador. Esta funçao freqüentemente
aparece em loop de repetições. Alguns exemplos são:
MPYA x ; ACC = ACC + P , P = x*T MPYS * ; ACC = ACC - P , P = T*(*AR(ARP)) SQRA y ; ACC = ACC + P , P = y*y SQRS *+ ; ACC = ACC - P , P = *AR(ARP)^2 e ; incrementa o AR corrente MPYU n ;mult não sinalizada: P = ABS(T*n)
5.3. OPERAÇÕES DE MOVIMENTAÇÃO DE BLOCOS
Desde que o C24x possui duas áreas de memória, às vezes se faz necessária a
transferência de arrays de uma determinada memória para outra. Duas instruções de blocos
estão disponíveis para facilitar a cópia de arrays.
• BLPD : Memória de programa para memória de dados
• BLDD : Memória de dados para memória de dados
Os comandos de movimentação de blocos na realidade copiam os mesmos (não
movem), e realizam uma operação única de memória e não em blocos. Porém quando
associadas à repetições, estas instruções podem efetivamente copiar um bloco de memória de
uma área a outra. Estas instruções necessitam de dois a três ciclos, mas quando aliadas à
repetição, somente a primeira vez requer múltiplos ciclos, as demais são executadas em ciclo
único.
30
Um processo de movimentação de blocos requer a especificação de três parâmetros:
• Localização do array a ser copiado
• Localização do destino desta cópia
• Número de palavras seqüenciais contidas neste array
A instrução de blocos especifica o fonte e o destino dos dados. O tamanho do bloco
deve ser especificado como argumento da instrução RPT.
5.3.1. BLPD - Memória de Programa para Memória de Dados
Nesta instrução dois operandos devem ser especificados:
1. Um endereço de um array na memória de programa
2. Um endereço de destino na memória de dados
O pma utiliza um endereçamento explícito de 16 bits. O dma pode ser especificado via
endereçamento direto ou indireto, embora o endereçamento indireto seja amplamente
utilizado, uma vez que podemos especificar cópias de endereços incrementáveis.
Figura 15 - Instrução BLDP Como na instrução MAC, desde que o PC é o único ponteiro para a área de programa
quando utilizado loop de repetição, o pma é auto incrementado após cada iteração; o conteúdo
original do PC é restabelecido após a instrução de blocos. O hardware de pilha não é utilizado
31
pela MAC ou pelos blocos. A figura 15 apresenta uma transferência utilizando-se a instrução
BLPD.
5.3.2. BLDD - Memória de Dados para Memória de Dados
Em algumas vezes se faz necessário realizar a cópia de uma determinada área da
memória de dados para alguma outra área na mesma memória. Um exemplo seria mover
informações entre as memórias on-chip e off-chip. A instrução BLDD realiza esta operação
quase da mesma forma que a BLPD, com as seguintes diferenças:
• Cada operando especifica uma dma
• O primeiro operando indica a fonte e o segundo, o destino
• Um operando é especificado via endereçamento imediato
• O outro é especificado via endereçamento direto ou indireto
Como na BLPD, o tempo de execução depende das posições da fonte e do destino, e é
executada em ciclo único quando aliada à RPT.
5.3.3. TBLW - Memória de Dados para Memória de Programa
Nesta instrução, o endereço da memória de dados é especificado pela instrução, e o
endereço da memória de programa reside nos 16 bits inferiores do acumulador. Uma leitura
da memória de dados é seguida de uma escrita na memória de programa. Quando estruturas
repetitivas são utilizadas, esta instrução é executada em ciclo único também e o contador de
programa que contém o ACCL é incrementado de um a cada ciclo.
5.3.4. TBLR - Memória de Programa para Memória de Dados
32
Esta instrução transfere uma palavra de uma posição da memória de programa para a
memória de dados especificada pela instrução. O pma é definido pelo ACCL. Para esta
operação, uma leitura da memória de programa é seguida de uma escrita na memória de
dados. Em modo repetitivo, a TBLR é executada em ciclo único e o PC que contém o ACCL
é incrementado de um a cada ciclo. Esta instrução possibilita efetuarmos a leitura de uma
tabela que foi inserida via software e armazenarmos o valor recolhido um uma variável da
memória de dados.
5.4. OPERAÇÕES DE I/O
O C24x possui duas instruções, IN e OUT, as quais permitem transferência entre
memória de dados e dispositivos de I/O. Estas instruções são ótimas para o uso com
conversores A/D e D/A paralelos. A sintaxe é:
IN dma, pa ;lê o dado de um periférico (pa) e armazenando na dma
OUT dma, pa ;escreve o dado da dma na porta (pa) para o periférico
Onde: dma - é um endereçamento direto ou indireto da memória de dados pa - é um valor de port address entre 0000h e 0FFFFh É importante lembrar que estas instruções operam somente entre a memória de I/O e a
memória de dados. A figura 16 apresenta um resumo das instruções desta seção.
33
Figura 16 - Resumo das Instruções de Movimentação de Memória
34
6. SISTEMAS NUMÉRICOS
Para se compreender perfeitamente os processos aritméticos que serão utilizados se
faz necessário uma pequena revisão dos conceitos numéricos binários.
6.1. NÚMEROS BINÁRIOS
A numeração binária é o esquema mais simples utilizado em computadores, e é a base
de muitos outros esquemas. Alguns detalhes sobre este sistema são:
• Possui somente dois valores: 1 ou 0
• Cada dígito binário, ou bit, representa um "nível" em um número binário que
representa uma potência de 2.
• O bit menos significante é o da direita (LSB)
• Os valores são representados pelo estabelecimento dos 1's no lugar apropriado
• O número de bits determina a faixa que pode ser representada
Exemplo:
0110 2 = (0*8) + (1*4) + (1*2) + (0*1) = 6 10
6.2. NÚMEROS EM COMPLEMENTO DE DOIS
Percebe-se que a utilização de números binários podem representar somente números
positivos pois:
(11110)2 = (1*16) + (1*8) + (1*4) + (1*2) + (0*1) = (30)10 ; para 5 bits
35
O complemento de dois modifica o sistema binário incluindo números negativos,
através da transformação do MSB em um número negativo:
(11110)2 = (-1*16) + (1*8) + (1*4) + (1*2) + (0*1) = (-2)10 ; para 5 bits
Caso o MSB seja zero, a representação continua sendo a mesma. Com isto,
reduziremos o pico da representação positiva de 16 bits que é 65536 (2^16) para 32768
(2^15) mas a faixa de variação continuará a mesma. Desta forma poderemos então representar
números negativos da mesma forma. Conforme a figura 17 mostra, os número entre 0000h e
7FFFh serão positivos pois MSB é zero para todos, e os números entre 8000h e FFFFh serão
considerados negativos.
Figura 17 - Normalização e Representação de Números Negativos
6.3. SIGN EXTENSION MODE
O processador inclui um modo específico de representação binária chamado de modo
de extensão de sinal (Sign Extension Mode). Podemos selecionar o modo de operação via
software através do registro SXM.
O modo SXM faz o acumulador (32 bits) operar em complemento de dois. A figura 18
apresenta os efeitos do modo SXM. Caso estejamos operando neste modo e carregarmos um
36
Figura 18 - Efeito do Modo SXM
número hexadecimal no acumulador, o bit mais significativo do número (bit 16) será
reproduzido nos demais bits do acumulador superior, preservando a informação do sinal do
referente número para podermos manipular livremente os shifts de forma a não perdermos
qualquer informação. Além do mais, esta é uma maneira de realizarmos a armazenagem de
um determinado número com total fidelidade da informação, pois a informação do sinal estará
no ACCH, possibilitando-se a manipulação dos shifts da forma desejada. Programa-se da
seguinte forma:
SETC SXM ; ACC opera em complemento de dois
CLRC SXM ; ACC opera em modo não sinalizado
Porém, problemas podem aparecer quando efetuamos a multiplicação de números em
complemento de dois. Considere o seguinte exemplo da figura 19 (o C24x não opera desta
forma, sendo apenas para fins ilustrativos):
Algumas dúvidas como por que o produto parcial final é diferente dos demais, ou será
que o resultado está correto, ou como armazenaremos o resultado novamente na memória.
Para esta última pergunta existem três possibilidades. A primeira seria armazenar somente a
parte baixa, o que traria erros pois estaríamos desprezando metade da informação, inclusive o
37
sinal do número. A segunda seria armazenar a parte alta do acumulador, mas de acordo com a
precisão necessária para a aplicação, isto não seria aconselhado. Por último, poderíamos
armazenar ambas as partes, o que acarreta em espaço extra de memória e cria novas questões,
como por exemplo, o que deveria ser feito para se reutilizar esta informação no caso de um
sistema realimentado.
Figura 19 - Multiplicação em Complemento de Dois
6.4. FRAÇÕES BINÁRIAS
Dados os problemas associados aos números inteiros e suas multiplicações, considere
a possibilidade de se utilizar números fracionários. Frações não crescem quando
multiplicadas, por isso, elas permanecem representáveis com o mesmo tamanho dado,
resolvendo um dos problemas. Porém existem alguns problemas; como seria a representação
de uma fração em complemento de dois e quais questões estão envolvidas na multiplicação de
frações.
38
6.4.1. Representação das Frações
Um meio encontrado de se representar frações em sistemas binários seria da seguinte
forma (modelo de 4 bits):
1011 2 = (-1*1) + (0*1/2) + (1*1/4) + (1*1/8) = -5/8
Isto é, o MSB continua carregando a informação do sinal e é multiplicado pelo
número inteiro 1. Os bits subseqüentes são então multiplicados pela metade do seu antecessor.
Desta forma, o intervalo possível de representação seria de -1 a +1.
Quando o C24x realiza uma multiplicação, o processo é o mesmo para todos os
operandos. Observe a figura 20:
Figura 20 - Multiplicação de Números Fracionários
Para se ler o resultado de uma multiplicação fracionária, se faz necessário se localizar
o "ponto binário". Inicia-se com os valores de entrada. O MSB é um inteiro, e o próximo bit é
1/2, então o ponto binário está entre eles. No exemplo anterior, haviam três bits após o ponto
binário em cada valor de entrada. Para uma melhor representação, podemos referi-los como
números Q3 onde Q indica o número de bits à direita do ponto. Quando multiplicados, os
valores Q são somados. Então, o resultado do exemplo anterior é um Q6.
39
Como nos inteiros, o resultado está nos bits inferiores, e o MSB é a extensão de sinal
do sétimo bit. Se este resultado fosse armazenado no acumulador, poderíamos armazená-lo na
memória de diversas formas:
• Armazenar ambos os acumuladores (H e L) o que traria maiores detalhes mas
incorreria nos problemas anteriores.
• Armazenar somente a parte alta (ou baixa) do acumulador, porém isto cria a
possibilidade de possuirmos vários tipos de Q's na memória.
• Armazenar a parte alta do acumulador deslocada de 1 bit para a esquerda. Isto
resultaria em armazenarmos números com o mesmo Q da entrada e com
igual precisão.
No nosso caso, os números de entrada seriam Q15 e o resultado da multiplicação seria
um Q31, devido à existência do bit de extensão de sinal.
Como se viu, é aconselhável realizar a terceira forma de armazenamento de
informação. Para realizarmos os deslocamentos existem três formas simples.
A primeira delas seria o shift explícito representado pelas instruções SFL ou ROL.
Considere o código:
; A * B = C LT A ; A e B são Q15 MPY B ; P = A*B : notação Q30 PAC ; ACC = A*B na notação Q30 SFL ; ACC = A*B na notação Q31 SACH C ; C = A*B na notação Q15 A segunda maneira é o shift na armazenagem
; A * B = C LT A ; A e B são Q15 MPY B ; P = A*B : notação Q30 PAC ; ACC = A*B na notação Q30
40
SACH C, 1 ; C = A*B na notação Q15
A terceira maneira é o Product Mode Shifter. Este deslocador está localizado entre o
registrador P e o mux de entrada da ALU. Este deslocador pode passar o produto sem shift, ou
pode realizar um deslocamento para a esquerda de 1 ou 4 bits, ou para a direita de 6 bits. O
deslocador é controlado pelo registro PM do status register 1 (ST1), o qual pode ser
modificado pela instrução SPM. A tabela a seguir indica os estados possíveis:
Tabela 3 -Estados PM e seus Efeitos
PM SHIFT 0 Sem shift 1 1 para esquerda 2 4 para esquerda 3 6 para direita
O código a seguir apresenta o mesmo resultado dos modos anteriores:
; A * B = C SPM 1 LT A ; A e B são Q15 MPY B ; P = A*B : notação Q30 PAC ; ACC = A*B na notação Q31 SACH C ; C = A*B na notação Q15
6.5. REPRESENTAÇÃO FRACIONÁRIA VS. INTEIRA
Como o acumulador do C24x é de 32 bits, adiciona uma faixa extra para o cálculo dos
inteiros, mas isto é um problema ao armazenarmos novamente na memória. Da mesma forma,
com o uso de frações, os bits extras do acumulador aumentam a precisão, o que ajuda a
minimizar erros acumulativos. Assumindo-se uma precisão de meio LSB, somando-se dois
destes valores produziria um erro de 1 LSB. Em 256 somas, oito LSB's seriam duvidosos.
41
Desde que o acumulador possui32 bits de informação, e o resultado fracionário está na parte
alta, isto reduz grande parte do ruído na informação em longas somas de produtos.
6.6. FRAÇÕES E O ASSEMBLER
Para a obtermos a representação válida de coeficientes fracionários na memória,
devemos realizar uma normalização destes valores como indica a figura 17 mostrada
anteriormente. Esta normalização deve ser feita para representarmos as frações como números
inteiros para podermos realizar operações com estes números. Note que a informação de
magnitude destes números em relação ao seu número fracionário foi somente escalonada.
Então, para exemplificar, queremos representar o número 0.6578 como um dos
coeficientes:
Basta declará-lo como - coef: .int 32768 * 6578 / 10000
Agora podemos efetuar as operações necessárias com relação a cada coeficiente, mas
o resultado estará também escalonado. Contudo, como o resultado estará disponibilizado no
acumulador (ACC) e este é um registro de 32 bits, podemos então manipular o resultado
obtido através de shifts e coletar somente a magnitude que nos interessa. Desta forma o
problema de representação pode ser solucionado com sucesso e o resultado será um número
de 16 bits e Q15 válido conforme a representação fracionária.
6.7. TRATANDO O OVERFLOW DE ADIÇÕES
Conforme demonstrado anteriormente, representar um número na forma de fração é
muito melhor do que na forma inteira. Uma Segunda consideração é para as adições. Embora
experimentos com frações estejam confinados a um intervalo quando multiplicadas, nenhuma
42
garantia é oferecida no caso da adição. Como muitos algoritmos do DSP são baseados em
soma de produtos, o usuário deve ser habilitado a realizar longas somas com resultados
confiáveis. Para isto, existem algumas técnicas que serão apresentadas.
6.7.1. Estabelecer o Headroom via PM Shifter (SPM3)
Vimos que este deslocador pode realizar um deslocamento de 6 bits para a direita.
Incluindo-se o bit de sinal e o bit de extensão de sinal no registrador de produto, um total de
8 bits inteiros estarão presentes no acumulador, ao utilizar-se o modo SPM3.
Estes bits extras são chamados de headroom ou guard bits. Com a utilização deste
método pode se realizar até 128 somas com uma entrada máxima sem que haja overflow no
sistema. Este método funciona bem na preservação dos dados que de outra forma poderiam
causar estouro no sistema, mas não fornece os resultados no formato Q15, o que o torna um
pouco inconveniente.
6.7.2. Overflow Mode
Como percebido, é possível se estabelecer oito bits inteiros no acumulador para
permitir a representação de número extensos. No entanto, ainda é possível que somas maiores
ainda sejam geradas, o que iria estourar o acumulador e produzir resultados errôneos.
Considere o seguinte:
0111 2 + 0001 2 = 1000 2 o que produz 7 + 1 = -8 ???
43
Obviamente, este resultado não é o desejado, mas é uma realidade no uso do
complemento de dois. No caso do C24x, o número de bits é maior (16 bits) mas o efeito é o
mesmo.
Na verdade, a representação dos valores possíveis é circular como mostra a figura 21.
Figura 21 - Representação Circular de Valores
Os maiores valores positivo e negativo são adjacentes, e não opostos. O C24x pode
ser programado para manipular este processo de duas formas:
• Permitindo a ocorrência do estouro através da instrução CLRC OVM
• Impondo um limite de saturação o qual impossibilita o acumulador a
ultrapassar a fronteira entre o valor mais positivo e o valor mais negativo,
através da instrução SETC OVM
Note que este método é utilizado quando o acumulador está operando em
complemento de dois, onde são representados números negativos. Caso o acumulador não
esteja operando em complemento de dois, o overflow não existirá. É necessário dizer que o
status do bit OVM não é especificado pelo reset, fazendo-se necessário defini-lo no programa.
44
6.7.3. Teste por Overflow
O C24x, existe um bit no status register que indica quando um estouro ocorreu (bit
OV). Uma vez setado, este bit permanece neste estado até que seja efetuado algum teste com
ele, ou o processador seja resetado. Um exemplo de teste seria :
BCND pma, OV
Uma vez realizado este teste, qualquer que seja o resultado do mesmo, o bit OV será
resetado. Este é um dos métodos mais utilizados para se manejar o overflow: testar e, se
necessário, escalonar o sistema da forma desejada.
Desta forma, o usuário deve ter em mente uma visualização bem clara dos objetivos
do projeto para se estabelecer quais modos serão utilizados e como será realizado o
tratamento das informações.
6.7.4. O que fazer com o Headroom (Solução SPM3 ativada)
Figura 22 - Imposição de Limite de Saturação
Conforme indicou a figura anterior, podemos limitar um sinal antes de enviá-lo a uma
saída através do valor de saturação. Analisando-se a rotina de saturação apresentada,
45
adicionando-se o valor 7F00 0000 (diferença entre o ACC máximo e o limite de um número
fracionário quando o modo SPM3 é selecionado) ao acumulador, valores maiores que o limite
fracionário serão forçados a 7FFF FFFF.
A segunda instrução subtrai o valor 7F00 0000 do acumulador. Para valores que não
excederam o limite fracionário, isto efetivamente desfaz a instrução anterior, mas para valores
que excederam o limite fracionário positivo, acumulador será carregado com o valor do
limite de saturação positiva.
As outras duas instruções possuem o mesmo efeito para o teste do limite negativo.
Com isso, valores entre os limites de saturação permanecem inalterados, ao passo que valores
que provocariam estouro são limitados ao valor de saturação.
6.8. A DIVISÃO NO C24X
O C24x não possui uma instrução explícita de divisão. Ao invés disto, o processo é
quebrado em uma série de subtrações e deslocamentos. Uma rotina eficiente e flexível pode
ser implementada através da instrução SUBC (subtração condicional), a qual implementa um
passo de um longo processo de divisão.
A instrução SUBC é um divisor de um bit. A cada passo da divisão, um teste deve ser
realizado para sabermos se o denominado "cabe" dentro do numerador. Após isto, uma
subtração é realizada e o resultado é testado a saber se é positivo. Se positivo, o denominador
"coube" no numerador. A subtração é então aceita e o valor 1 é carregado no ACCL (após se
deslocar o ACC de um à esquerda) para se identificar o teste positivo. Se o teste for negativo,
o denominador "não coube" no numerador. Neste caso, o valor anterior do acumulador é
46
restaurado com um left shift e um zero é colocado no LSB para identificar que o teste falhou.
Este deslocamento do acumulador permite que um novo bit da divisão seja testado.
Após n subtrações condicionais serem realizadas, o resultado de n-bits da divisão de
dois operandos estará no ACCL com nenhum bit remanescente presente no ACCH.
6.8.1. Divisão de Inteiros
As figuras a seguir ilustram o processo de divisão de inteiros e um exemplo de código
para se efetuar esta divisão.
Figura 23 - Divisão de Inteiros
47
Figura 24 - Exemplo de Código para Divisão
Note que a instrução SUBC opera apenas com números não sinalizados, então a
divisão deve ser precedida de uma rotina para determinar o sinal do resultado e retirar o sinal
dos operandos antes de se efetuar a divisão. Uma vez que já ocorreu a divisão, o sinal correto
é anexado ao resultado.
6.8.2. Divisão de Frações
A divisão de frações é idêntica ao processo dos inteiros, com duas exceções:
• O numerador é carregado no ACCH
• Somente n-1 iterações devem ser realizadas para uma fração de n-bits. O
quociente está no ACCL é o resto estará no ACCH
48
Figura 25 - Divisão de Frações
Figura 26 - Exemplo de Código para Divisão de Frações
49
7. OPERAÇÕES LÓGICAS
Antes de discutirmos as operações lógicas disponíveis na ALU, é preciso analisarmos
as posições dos operandos de fonte e destino. Esta informação é comum a todas as operações
lógicas e constitui:
• O primeiro operando deve estar no acumulador
• O segundo operando (se existir) é proveniente da saída do deslocador que por
sua vez pode operar com as memórias de dados e programa
• O destino dos dados é sempre o acumulador
7.1. OPERAÇÕES BOOLEANAS
As operações mais populares são o AND, OR e XOR. A tabela a seguir ilustra os
modos de se utilizar estas operações aliado aos tipos de endereçamentos.
Tabela 4 - Operações Booleanas e suas Utilizações
Direto Indireto Imediato AND x AND * AND #12 OR y OR *+ OR #7035 XOR c XOR *0-, AR2 XOR #0FFFFh,5
# = constantes = 2 ciclos
7.2. SHIFT E ROTATE
A ALU suporta deslocamentos e rotações de até 32 bits, neste caso operando com o
acumulador. Este por sua vez pode ser deslocado de um único bit, tanto para a direita com a
instrução SFR (shift right), como para a esquerda com a instrução SFL (shift left). Em ambos
os casos, o bit deslocado do acumulador é inserido no bit de carry do acumulador. No caso
50
de um deslocamento para a esquerda, o LSB é preenchido com um zero e a instrução não é
afetada pelo SXM. No caso de um deslocamento para a direita, o MSB pode ser preenchido
com um zero ou com uma extensão do sinal dependendo do bit SXM.
O acumulador pode ser rotacionado em conjunto com o bit de carry através das
instruções ROR (rotate right) e ROL (rotate left). A instrução ROR realiza a rotação do
acumulador para a direita, fazendo com que o bit de carry se torne o MSB e o LSB se torne o
bit de carry. A instrução ROL realiza a rotação para a esquerda, fazendo com que o MSB
torne-se o carry e o carry anterior se torne o LSB.
7.3. INSTRUÇÕES CMPL, NEG E ABS
A instrução CMPL realiza o complemento do operando presente no acumulador. A
instrução NEG realiza o complemento de dois do operando presente no acumulador. E a
instrução ABS torna o valor presente no acumulador em valor absoluto.
7.4. EXTRAÇÃO DE BITS
O C24x possui duas instruções especiais para testar o estado de um único bit na
memória: BIT e BITT. Estas instruções copiam o bit específico (0 a 15) no bit TC do status
register ST1. Mais a frente, será possível realizar branches de acordo com o estado do bit TC.
O bit a ser testado é especificado por um número de 4 bits (2^4 = 16 bits) o qual pode estar
indicado diretamente na instrução ou especificado indiretamente pelo registrador T (BITT). A
seguir constam alguns exemplos genéricos:
51
BIT dma, bit code ; copia bit especifico da dma para o bit TC
BITT dma ; copia o bit indicado pelos 4 LSB's do regis- ;trador T da dma para o TC BCND pma, TC ; pule se TC = 1 BCND pma, NTC ; pule se TC = 0
7.5. COMPARAÇÃO DE PONTEIROS
Anteriormente foram descritas duas das três funções do AR0. A terceira função
permite que o AR0 seja comparado com o conteúdo do AR corrente, às vezes referido como
AR(ARP). A instrução CMPR é utilizada com um operando de dois bits, que especifica a
condição de teste. O resultado do teste é colocado no bit TC. Esta instrução é mais utilizada
para se especificar um loop com um valor diferente de zero. Então:
CMPR cm
Se cm = 00b, teste se o (AR corrente) = (AR0) Se cm = 01b, teste se o( AR corrente) < (AR0) Se cm = 10b, teste se o( AR corrente) > (AR0) Se cm = 11b, teste se o( AR corrente) != (AR0) Se verdadeiro, TC = 1 Se falso, TC = 0
52
8. WATCHDOG TIMER
Este timer fornece uma segurança contra perda da CPU, através de um reset
automático caso não seja avisado pela CPU em intervalos regulares de tempo. Em controle de
motores, isto ajuda a proteger o motor e os drivers eletrônicos quando o controle se perder.
Qualquer reset da CPU reverte as saídas PWM para o estado de alta impedância, o que irá
desligar os conversores de potência e evitará a danificação do sistema.
Este timer sempre se encontra habilitado e não poderá ser desabilitado pelo usuário
(exceto durante a programação da FLASH). Isto deve ser definido via software logo após o
sistema seja ligado ou resetado. Especificamente, o usuário possui 6.55 ms após qualquer
reset, antes que o cão de guarda inicie um reset. Para um clock de 50 ns, isto indica cerca de
130.000 ciclos . Isto é tempo o suficiente para se configurar o timer como desejado. Uma
falha no software pode causar um loop infinito de resets. As figuras a seguir indicam os
registradores referentes ao temporizador e os possíveis efeitos.
Figura 27 - Períodos de Seleção
53
É importante lembrar que o kit utilizado (DSK) possui um programa monitor que é
executado a cada power-up ou reset que desabilita o watchdog timer. Então, este está sempre
desabilitado no DSK.
Figura 28 - Registrador de Controle do WD
Figura 29 - Conseqüências de Escritas no Campo WDKEY
Outros fatos de menor importância são a presença de um multiplicador interno de
clock (4x) que determina os 20 MHz, pois o único elemento necessário para tal é um cristal
externo de 5 MHz, e a existência do modo de baixo consumo, onde você pode colocar o
processador para "dormir" e este será acordado somente por interrupções habilitadas,
conforme indica a figura a seguir:
54
Figura 30 - Controle do Modo de Baixo Consumo
Figura 31 - Tabela de Eventos e seus Efeitos
55
9. INTERRUPÇÕES
As interrupções são os meios pelos quais podemos desviar o fluxo normal de um
programa de acordo com a ocorrência de determinado evento desejado. Elas podem ser
utilizadas por dispositivos que necessitam recolher ou fornecer dados à CPU. Um exemplo
seriam os conversores A/D e D/A. O C24x suporta seis interrupções mascaráveis, o reset, uma
interrupção não mascarável e uma interrupção de proteção dos drivers.
9.1. RESET
O reset é uma interrupção não mascarável que pode ser iniciada por duas fontes
diferentes, um pino externo que é acionado por nível baixo, e pelo temporizador WD. O reset
é realizado no power up para assegurar o início em um estado conhecido. Desta forma:
- Qualquer programa é abortado imediatamente no reset
- O PC começa o fetching no pma 0000h
- Vários bits da CPU são inicializados em um estado definido
Estes bits são:
Status Register 0 (ST0):
OV = 0; INTM = 1;
Status Resgister 1 (ST1): CNF = 0; SXM = 1; XF = 1; PM = 0; C = 1;
Registradores de Interrupção:
56
IFR = 0; IMR = 0; Registradores de Controle de Interface: WSGR = FFFFh; GREG = 0;
9.2. ESTRUTURA DAS INTERRUPÇÕES
O processo de interrupção pode ser quebrado em uma série de passos que ocorrem de
forma seqüencial. A figura abaixo mostra o conceito de como as interrupções são
processadas.
Figura 32 - Esquema Conceitual das Interrupções
Analisando-se sua estrutura de periféricos nota-se que, sem uma boa diferenciação dos
eventos, o processo de análise dos mesmos tornar-se-ia muito complexo. Por isso, a própria
organização interna do processador trata de forma extremamente eficiente todos os
acontecimentos relativos aos seus periféricos . Esta diferenciação é feita através dos esquemas
de interrupção.
57
Este esquema de interrupção é hierarquizado, ou seja, é dividido em vários níveis. No
nível mais baixo, ou nível do periférico, o sistema é responsável por captar todos os
acontecimentos relativos a cada tipo de evento. Um exemplo seria a ocorrência de um
overflow do timer1. Neste caso, o bloco responsável pelo gerenciamento deste nível (IRQ
Pulse Generator Unit) seta o bit de flag correspondente na respectiva palavra de controle do
nível. O mesmo bloco analisa a palavra de máscara do nível e, caso esta interrupção periférica
não esteja mascarada, é gerado então um sinal de IRQ (Interrupt Request) para o nível
superior. Na hierarquia periférica temos seis diferentes tipos de níveis os quais diferem em
suas prioridades de tratamento e valor de vetor (PIVR). Dentro destes seis níveis temos ainda
outros níveis que, agora sim, correspondem aos eventos em si, o que corresponde ao níveil
mais baixo da estrutura.
Uma vez que o evento ocorreu e a interrupção não está mascarada, o correspondente
bit é setado no registrador PIRQ (nível superior ao nível periférico) e o sinal é
automaticamente repassado à CPU. A estrutura de interrupções da CPU possui seis níveis
(INT1 a INT6) podendo cada uma delas ser mascarada ou não.
Com a chegada do sinal de interrupção a CPU seta o correspondente flag no registro
de flags de interrupção (IFR) e analisa o registrador de máscara de interrupção (IMR). Caso a
interrupção esteja desmascarada e o bit INTM (enable all) do ST0 esteja zerado, a CPU faz o
reconhecimento da interrupção (Interrupt Acknowledge) através do envio do sinal de ACK no
barramento de dados e da colocação do correspondente valor no vetor de interrupção
periférica (PIVR), que será colocado então no barramento de endereçamento.
O registrador PIVR possibilita o tratamento diferenciado para cada ISR. Através do
vetor de interrupção da CPU, o programador pode diferenciar cada GISR (Global Interrupt
Service Routine) que é onde ele tratará os acontecimentos de interrupção no nível superior
58
(INT1 a INT6), através das instruções de branches para as determinadas GISR's em cada
posição correspondente na memória. Serão nestas rotinas que o programador deverá tratar
também o "pulo" para cada SISR (Specific Interrupt Service Routine). Ele fará isto retirando o
valor de PIVR corrente e comparando com os possíveis vetores que ele próprio teria
habilitado pelo registro de máscaras de interrupção.
É importante dizer que o programador deve se responsabilizar pela limpeza dos flags
ao término do tratamento de cada tipo de interrupção que possa vir a ser útil no processo de
desenvolvimento do software.
Para evitar a parada do sistema em um estado não previsto, é aconselhável a criação
de uma SISR para as demais int's que não serão utilizadas mas que por ventura possam vir a
ser reconhecidas pela CPU, mesmo sem habilitação de suas máscaras. A figura 33 apresenta
uma fácil visualização das hierarquias e a figura 34 mostra como elas se relacionam.
Figura 33 - Estrutura de Hierarquias de Interrupções
59
Figura 34 - Funcionamento da Diferenciação de Eventos
Este esquema bastante eficiente e de fácil compreensão é que possibilita um
tratamento tão eficaz das ocorrências de eventos e, com isso, ganha-se em performance de
operação do processador e do sistema , e domínio total sobre as atribuições a cada tipo de
processo envolvido na criação da máquina como um todo.
Para uma visualização de como gerenciar uma interrupção pela programação, vamos
supor que queiramos ativar uma interrupção de underflow do timer1. Seguindo os passos
indicados anteriormente, devemos observar inicialmente os requisitos no nível periférico.
Neste nível existe o registrador de máscara do periférico chamado de EVIMRB. Observando
este registro e o que cada bit significa, podemos desmascarar a interrupção relativa ao evento
desejado. Este mesmo nível possui uma palavra de flags conhecida como EVIFRA que é onde
a CPU seta determinados bits correspondentes à ocorrência de determinados eventos.
60
Habilitado o nível inferior, passa-se ao nível imediatamente superior a este. Neste nível,
precisamos saber qual evento pertence a qual tipo de interrupção (no nosso caso, a INT2 deve
ser a selecionada), para podermos habilitá-la através do registro IMR. Este nível possui ainda
uma palavra de flags, os quais serão setados na ocorrência de eventos relativos às
interrupções correspondentes (IFR).
Desta forma, teremos em termos de código:
.setsect ".vectors",8000h .sect ".vectors" RSVECT B START ;reset = pulo para inicio INT1 B PHANTOM ;pulo para rotina de retorno INT2 B GISR_INT2 ;pulo para tratamento underflow timer 1 INT3 B PHANTOM ;pulo para rotina de retorno _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ .setsect ".text",2000h .text LDP #232 ; Data Page dos registros a seguir SPLK #200h,_EVIMRA ;habilita T1UFINT SPLK #0FFFFh,_EVIFRA ;limpa flags LDP #0 ; Data Page dos registros a seguir SPLK #00FFh,_IFR ;zera flags de IFR SPLK #0002h,_IMR ;habilita INT2 de IMR
Desta forma habilitamos o reconhecimento da interrupção T1UFINT. Agora devemos
preparar o tratamento da ocorrência da mesma. Fazemos isto da seguinte forma:
GISR_INT2: SETC INTM LDP #224 LACL _PIVR ;carrega valor de PIVR XOR #0029h ;compara com vetor de T1UFINT BCND INVERSOR,EQ ;se igual pule para SISR CLRC INTM
61
RET
Note que anteriormente desviamos a ocorrência de uma INT2 para a linha
GISR_INT2. Nesta parte comparamos com o vetor de interrupção (PIVR) desejado. O 29h é o
vetor carregado em PIVR quando um evento do tipo T1UFINT é detectado. Comparamos o
PIVR com este valor e em seguida promovemos outro pulo para um tratamento específico, de
acordo com a comparação obtida. Note que podemos comparar com vários valores de PIVR,
onde o que indica quem será tratada primeiro é a prioridade de cada evento. Desta forma
podemos diferenciar inúmeros eventos e tratá-los de forma eficaz. Existe farta bibliografia no
setor a respeito desta parte.
Figura 35 - Gerenciamento de Interrupções
9.3. VETORES DE INTERRUPÇÃO
Após uma interrupção ser reconhecida, o PC é carregado com o endereço
correspondente do vetor de interrupção mostrado na figura abaixo. O usuário deve mapear
uma configuração de branches para as rotinas apropriadas a partir do endereço 0000h.
62
Note que no código exemplificado anteriormente, escrevemos os pulos a partir do
endereço 8000h. Isto foi feito pois o programa monitor do DSK ocupa a área correspondente
ao vetor de interrupção, deslocando-o para a partir do endereço 8000h.
Figura 36 - Endereços do Vetor de Interrupção
Aconselha-se efetuar o salvamento de contextos que possam vir a ser alterados pela
execução de uma ISR e que são importantes para a execução do programa principal.
Exemplos seriam os AR's, os registradores matemáticos como P ou ACC, e os registradores
de estado. Neste último caso, existem instruções específicas para tal. A instrução SST salva o
determinado status register em uma dma, e a instrução LST carrega o determinado status
register com a dma definida na instrução.
9.4. INTERRUPÇÕES ANINHADAS
Em algum instante do programa a CPU pode estar tratando uma determinada ISR
quando uma interrupção de maior prioridade ocorre. Isto causa a parada do tratamento da
rotina sem esta se completar. O C24x já prevê este tipo de acontecimento. As duas coisas que
o usuário precisa adicionar à ISR para habilitar interrupções aninhadas são:
• Repriorizar interrupções via IMR
63
• Reabilitar as INT's via INTM
Modificando-se IMR garante-se que somente uma determinada interrupção ou
nenhuma interrupção quebrará a execução da ISR corrente. Modificando-se INTM garante-se
que nenhuma interrupção quebrará a rotina corrente.
9.5. INTERRUPÇÃO DE PROTEÇÃO DOS DRIVERS - PDPINT
O pino PDPINT fornece uma interrupção especial para implementar uma proteção de
sobrecorrente que difere da utilização de outras interrupções externas (XINT1, XINT2).
Quando um sinal válido ocorre no pino PDPINT (nível baixo por no mínimo 4 ciclos), duas
ações paralelas são tomadas. A primeira é tomada pela lógica dedicada que coloca todas as
saídas PWM em alta impedância em aproximadamente 45-55 ns. Este caminho especial via
hardware evita o atraso do objetivo caso fosse necessário realizar a ação via software. Além
do mais, o caminho via hardware independe do clock da CPU, operando até mesmo uma falha
do mesmo. A segunda ação é uma requisição de interrupção à CPU .
É importante salientar que estas duas ações da PDPINT podem ser desabilitadas
através do bit PDPINT Enable no EVIMRA. No entanto, uma vez habilitada, a alta
impedância ocorrerá sem ser afetada por IMR e INTM, que afetam somente a segunda ação.
9.6. INTERRUPÇÕES VIA SOFTWARE
O C24x também fornece facilidades para se invocar ISR's sobre controle via software.
A figura a seguir ilustra a instrução INTR e os seus efeitos.
64
Figura 37 - A Instrução INTR
Existe também a instrução TRAP que transfere o controle para a pma 22h. esta
instrução pode ser usada para debugar um programa, mas sua utilização não é aconselhada,
uma vez que o ambiente do kit já fornece esta opção.
65
10. O MÓDULO GERENCIADOR DE EVENTOS (EVM)
Figura 38 - Esquema em Blocos do EVM
Conforme descrito anteriormente, o módulo EVM possui dois timers de uso geral,
comparadores/PWM's, unidades de captura e circuitos codificadores de pulso por quadratura.
Este módulo merece atenção especial pois é ele quem fornece a possibilidade de
implementação do projeto, dentro das metas pré estabelecidas para o mesmo.
A estrutura dos dois timers de uso geral são quase idênticas e possui as seguintes
características:
66
• Um timer de 16 bits, contador com modos de contagem tipo subida/descida e
registrador TxCNT para leitura e escrita;
• Única palavra de controle para configuração dos dois timers (caso F243)
• Registrador de 16 bits para comparação com valor do contador (TxCMPR)
para leitura e escrita;
• Registrador de 16 bits de período de contagem (TxPR) para leitura e escrita;
• Registrador de 16 bits de controle (TxCON) para leitura e escrita;
• Prescaler programável para clock interno ou externo;
• Controle e interrupções para quatro tipos de interrupção: underflow, overflow,
timer compare e period match.
• Pino de seleção de direção (TDIR) para o caso de contagem direcional.
Os timers de uso geral podem ser operados de modo independente ou sincronizados
entre si. O registrador de comparação associado a cada timer pode ser usado para função de
simples comparador ou para geração da forma de onda PWM.
Figura 39 - O Tempo Morto Conforme citado anteriormente, existem três unidades conhecidas como full compares
com base de tempo relacionada ao timer 1 que poderão gerar seis saídas comparadoras ou seis
67
saídas PWM's com circuito de tempo morto programável. Cada uma destas saídas pode ser
configurada independentemente. O tempo morto, que deve existir nos sinais de comando dos
fets de um mesmo braço, serve para garantir comutação sob tensão nula e evitar curto-circuito
de braço. A figura 39 apresenta circuito do tempo morto (deadband) e sua funcionalidade.
Cada GP-Timer possui a sua própria configuração de interrupções, as quais são
individualmente mascaráveis. São elas:
• TxPINT - interrupção por casamento de período. Seta o flag correspondente
• TxUFINT - Interrupção por underflow
• TxOFINT - Interrupção por overflow
10.1. MODOS DE OPERAÇÃO
Conforme indicado anteriormente, os timers de uso geral possuem quatro modos
diferentes de operação. O mais simples é o modo Stop/Hold onde a operação do timer fica
parada no seu estado corrente. O contador, a saída comparadora e o prescaler permanecem
inalterados.
Dois dos três modos restantes são freqüentemente utilizados na obtenção do PWM. A
exceção é o modo de contagem direcional up/down. Este modo permite a utilização de um
sinal externo tanto para o clocking de contagem como para direção. A seguir, será dada maior
ênfase para os modos que são interessantes para a aplicação.
68
10.1.1. Modo Continuous-Up
Figura 40 - O Modo Continuous Up
O procedimento deste modo de contagem é o seguinte:
• O usuário seta o bit 6 do TxCON para iniciar a contagem
• Esta começa na próxima borda de subida do clock
• A primeira contagem sempre será zero
• Incrementa contagem até igualar ao registrador de período
• Se o contador for maior que o período, conta até FFFFh
• Na próxima borda de subida:
- O contador é resetado
- A contagem continua da mesma forma
10.1.2. Modo Continuous-Up/Down
O comportamento de tal modo é o seguinte:
• O usuário seta o bit 6 do TxCON para iniciar a contagem
• A contagem inicia na próxima borda de subida do clock
69
• Primeira contagem é zero
• Contagem é incrementada até se igualar ao registrador de período, então
retorna os valores até chegar a zero novamente
• Se o contador for maior que o período, este contará até FFFFh e então reseta a
contagem, iniciando nova contagem do valor zero
10.2. A MODULAÇÃO PWM
A modulação por largura de pulso é um método de representação de um sinal
analógico com aproximação digital. O sinal PWM consiste de uma seqüência de pulsos de
largura variada com amplitude constante, onde o sinal possui a mesma energia do sinal
analógico original.
Figura 41 - Modulação PWM
O C24x é capaz de gerar cinco saídas PWM independentes, com cerca de duas
freqüências de portadoras diferentes. As outras três saídas PWM restantes são
complementares a três das cinco anteriores.
Dois tipos diferentes de comparação existem no C24x:
70
• Comparadores do GP Timer
• Full compares
Como no caso dos registradores de período, existem buffers também para cada um dos
registradores de comparação. Via software, o usuário escreve um novo valor no compare
register buffer, donde o registrador TxCMP irá retirar automaticamente o próximo valor de
comparação, de acordo com um dos tr6es eventos selecionados. É importante lembrar que a
escrita é feita no registro TxCMP, e a expressão double buffered indica que o valor só será
mudado após a utilização do valor corrente.
Cada timer possui seu próprio gerador de forma de onda PWM, esta podendo ser
simétrica ou assimétrica. O gerador PWM utiliza o sinal proveniente do comparador como
uma entrada, e fornece como saída um sinal PWM para a unidade de saída lógica. Esta
unidade por sua vez fornece ao usuário a capacidade de escolher a polaridade do sinal TTL
que estará disponível no correspondente pino de saída, ou automaticamente forçá-lo aos
níveis baixo ou alto. O registrador GPTCON apresentado a seguir na figura 43 controla estas
capacidades. Também serão apresentadas as figuras 44 e 45, que ilustram as funções dos bits
do registrador TxCON.
Figura 42 - Registradores do Timer
71
Figura 43 - Registrador GPTCON
Figura 44 - Registrador de Controle do Timer ( parte alta )
Figura 45 - Registrtador de Controle do Timer ( parte baixa )
72
Desta forma, configurando-se os registradores da maneira desejada, pode-se obter
facilmente a forma de onda PWM.
10.3. FREQÜÊNCIA DE CHAVEAMENTO
A freqüência da portadora PWM é determinada pelo valor contido em TxPR, e pela
freqüência do sinal de clock ( no caso 20 MHz). Por exemplo, suponha a necessidade de gerar
uma portadora de 20 KHz. O valor necessário para TxPR é então:
PWM Assimétrico: T1PR = (período desejado/período processador) - 1
T1PR = ( 50 µs/ 50 ηs) - 1 = 999d = 3E7h
PWM Simétrico: T1PR = (período desejado/2 x período processador)
T1PR = ( 50 µs/ 2 x 50 ηs) = 500d = 1F4h
Note que no caso simétrico (triangular), o valor do período é metade do valor no caso
assimétrico (dente de serra).
Uma vez especificado o valor do registrador de período, a resolução do comparador
PWM pode ser calculada. Utiliza-se a potência de dois para tal. No exemplo acima:
PWM Assimétrico: resolução de 10 bits (2^10 = 1000)
PWM Simétrico : resolução de 9 bits (2^9 = 512)
10.4. CICLO DE TRABALHO
A determinação do ciclo de trabalho parte do princípio que o PWM começa inativo
durante certo período de tempo até a ocorrência da primeira comparação, quando torna-se
ativo. Para o exemplo anterior, suponha um duty cycle de 75%. O registrador de comparação
deverá ser carregado com os seguintes valores:
73
PWM Assimétrico: TxCMP = (100% - duty cycle) x T1PR = 0Fah
PWM Simétrico: TxCMP = (100% - duty cycle) x T1PR/2 = 3Fh
Note que para um PWM simétrico, o ciclo de trabalho desejado é atingido somente se
o registrador de comparação conter o mesmo valor para a subida de contagem e para a descida
da mesma.
10.5. PWM VIA FULL COMPARES
Figura 46 - Diagrama em Blocos do Full Compare
Podemos obter a modulação PWM através de unidades dedicadas a tal objetivo. Estas
unidades são conhecidas como full compares.
Existem três unidades comparadoras deste tipo. Estas unidades possuem capacidades
além dos comparadores comuns dos GP Timers. As características destas unidades são:
• Dois pinos de saída por unidade comparadora, onde uma saída é complemen-
tar à outra
• Possui a capacidade de se criar um espaço de vetores (controle vetorial)
• Possui hardware dedicado à função de geração de tempo morto (deadband)
• A operação dos comparadores é a mesma descrita anteriormente
74
A seguir estão listados os registradores referentes à estas unidades.
Figura 47 - Registrador de Controle dos Comparadores
Figura 48 - Registrador de Controle de Acionamento dos Pulsos
75
10.6. O TEMPO MORTO
Para a nossa aplicação, o estabelecimento do tempo morto é extremamente importante,
pois este garante a comutação dos elementos de um mesmo braço sob tensão nula, evitando o
curto circuito do braço do inversor. A sua funcionalidade foi apresentada anteriormente, bem
como a sua implementação interna. Nesta seção será tratada o estabelecimento deste tempo
morto via software, o que é extremamente simples.
Figura 49 - Registrador de Controle do Tempo Morto
Cada unidade full compare possui o seu próprio gerador de tempo morto, dividindo
somente a unidade de presacaler de clock e o período deste tempo morto entre si. Este tempo
morto pode ser habilitado individualmente para cada unidade. O tempo morto mínimo
diferente de zero corresponde ao período da CPU (50 ηs) e o máximo é 0.8 µs (16 x 50 ηs).
76
11. MÓDULO ADC (ANALOG TO DIGITAL CONVERTER)
Figura 50 - O Módulo ADC
A figura 50 mostra o diagrama em blocos funcional do módulo ADC. Este
módulo consiste de um conversor A/D de 10 bits, com um circuito segurador de ordem zero
interno. Possui um total de oito canais de entrada que estão multiplexados. O tempo máximo
de conversão de cada unidade ADC é de 1 µs, mas tipicamente a conversão leva 800 ηs para
77
ser realizada, e as tensões de referência vão de 0V a 5V e são supridas internamente. O
conversor é capaz de realizar duas conversões consecutivas de dois canais independentes,
com um tempo total de 1600 ηs. A precisão absoluta de cada conversor é de 1 LSB. Isto
significa que, por exemplo, caso o valor convertido devesse ser 2FFh, a conversão pode
retornar 2FEh, 2FFh ou 300h.
As funções inclusas no módulo ADC são:
• A unidade pode fornecer conversão única (single) ou contínua. Quando no
modo contínuo, o conversor gera dois resultados a cada 1700 ηs (prescale 1).
Estes resultados podem ser de duas entradas distintas;
• A conversão pode ser disparada por software, sinal externo ou por um certo
evento do módulo EVM;
• O registrador de controle do ADC pode ser configurado a qualquer momento;
• No caso de conversão simples, um pedido de interrupção é gerado ao término
da conversão caso esteja desmascarada, mas o correspondente bit é setado;
• Possui dois registradores de resultados do tipo FIFO;
• Os resultados anteriores serão perdidos quando um terceiro valor for
convertido e o primeiro ainda não foi lido.
Com estas propriedades mais a de ser baseado em um string/capacitor de 10 bits
que prevê a função de sample/hold, este periférico comporta-se como se houvessem dois
"pseudo" conversores, mas realmente existe apenas um conversor. Com isto podemos ter dois
resultados em um intervalo de tempo muito pequeno. Podemos também fornecer as tensões de
referência de maneira externa através das entradas VREFLO e VREFHI.
78
Com esta análise superficial da tecnologia envolvida no processo de controle,
elucida-se o motivo pelo qual escolheu-se o TMS320F243 para ser o elemento chave do
projeto, fornecendo todas as justificativas necessárias para a sua escolha pois este processador
supre todas as necessidades para implementação da nossa máquina.
Figura 51 - Registrador 1 de Controle do AD ( cima )
Figura 52 - Registrador 1 de Controle do AD ( baixo)
79
Figura 53 - Registrador 2 de Controle do AD ( cima )
Figura 54 - Registrador 2 de Controle do AD ( baixo )
80
Figura 55 - Registradores de Dados do AD
Figura 56 - Deslocando os Bits de Informação
81
Figura 57 - Leitura para o Formato Fracionário
Figura 58 - Exemplos de Código para o Formato Fracionário
82
12. O KIT DSK
Esta seção trata das especificações e limitações relativas à plataforma de
desenvolvimento de software que foi utilizada durante a realização dos testes e que foi
adquirida da empresa americana Spectrum Digital
Figura 59 - Diagrama em Blocos do Kit
12.1. CARACTERÍSTICAS GERAIS
A terminação DSK refere-se à "TMS320F243 DSP Starter Kit".
O kit DSK consiste de uma placa de circuito impresso confeccionada em multi-
camadas e um pacote de softwares de operação. Este conjunto permite avaliar de forma
prática certas características do TMS320F243 para determinar se este processador se encaixa
nas necessidades da aplicação. É importante dizer que ele permite quase total verificação das
propriedades do processador.
83
O kit DSK possui as seguintes características:
• Um processador TMS320F243;
• Uma interface de comunicação serial RS-232 com o PC;
• RAM selecionável (programa/dados) de 32K on board;
• Memória Flash de 8K on chip;
• Cristal de 5 MHz (DSP possui multiplicador interno x 4);
• Três conectores de expansão (Analog, I/O, Expansion);
• Conexão JTAG IEEE 1149.1 para emulação (on board);
• Operação em 5 V com um adaptador AC;
• Cabo serial de 9 pinos;
• Ambiente amigável de debugger ( Code Explorer e Code Composer);
• Assemblador SD24XASM;
• Compatível com Code Composer;
• Compatível com o TI 'C' Compiler/assembler/linker.
A figura 59 mostra o diagrama em blocos do DSK.
A fonte do kit fornece uma corrente máxima de 1 A, e a unidade requer apenas 150
mA.
No início da memória flash está inserido o programa monitor do kit que tem por
função efetuar a comunicação com o computador (host) através da porta serial. Desta forma o
usuário poderá desenvolver os softwares no microcomputador e poderá debugá-los
imediatamente no DSK. O software desenvolvido será sempre carregado na RAM da placa
(on board).
84
Com relação à memória de programa, uma peculiaridade que esta apresenta é possuir
imagens duplicadas da área referente aos endereços 0x8000h - 0xBFFFh nos endereços
0x4000h - 0x7FFFh e 0xC000h - 0xFDFFh. Então, caso o software esteja utilizando a posição
8000h e 8001h (INT1), o programador deve estar atento à este fato, pois ele não poderá usar
as posições 4000h e 4001h, nem C000h e C001h. A figura 60 mostra a configuração da
memória de programa.
Figura 60 - Memória de Programa do Kit
Pelo fato do vetor de interrupção estar na memória flash, o usuário não possui acesso
à ele via serial. Em adição, o programa monitor utiliza o vetor de power up e o vetor de
UART on chip. Por isso, todos os vetores são redirecionados para o endereço inicial
0x8000h na memória de programa mais o deslocamento referente ao vetor. O que isto
quer dizer em termos práticos é que, por exemplo, para efetuarmos o tratamento da
interrupção INT2, é necessário escrever na posição 0x8004h uma instrução de pulo para a
nossa GISR explicada anteriormente uma vez que as posições 0x8000h e 0x8002h pertencem
85
Figura 61 - Memória de Dados do Kit
aos vetores de RESET e INT1 respectivamente. Conforme elucidado, os vetores reais estariam
no início da flash, mas ao invés disto, existe uma instrução de pulo para a região de início
0x8000h nesta área.
Com relação à memória de dados, parte dela é utilizada pelo programa monitor para
alocação de variáveis dinâmicas. A carcterística mais importante é a possibilidade de se
86
utilizar uma memória externa (off board) na posição 0xC000h - 0xFFFFh com a escrita de
000C0h no registrador GREG. A figura 61 mostra a organização da memória de dados.
Tabela 5 - Jumpers de Configuração do Kit
Jumper Tamanho Função Posição de Fábrica JP1 1x3 MP/MC Mode 2-3 JP2 1x3 Vpp/Watchdog 1-2 JP3 1x3 Fonte VREFLO 1-2 JP4 1x3 Fonte VREFHI 1-2 JP5 1x3 Fonte da UART 2-3
O F243 DSK possui cinco jumpers os quais determinam quais características do kit
serão utilizadas. Cada jumper do DSK é do tipo 1x3 podendo ter a seleção 1x2 ou 2x3 e a
tabela 5 mostra uma tabela contendo suas funções e configurações padrão. O jumper 1 é
utilizado para se estabelecer o modo de operação, podendo ser microprocessador ou
microcontrolador. O jumper 2 é usado para selecionar a tensão de programação da flash ou a
operação do watchdog timer. Se a posição do jumper for 1-2 Vpp estará ativo e o watchdog
estará inativo. Na outra posição o padrão é invertido. Na realidade, o programa monitor é
quem desabilita o watchdog timer na configuração padrão. O jumper 3 é usado para
selecionar a fonte de VREFLO (tensão de referência baixa do módulo ADC). Na posição
padrão, a tensão é proveniente da placa. Na outra posição, a tensão deverá ser suprida de
modo externo. O jumper 4 é utilizado para selecionar a fonte de VREFHI (tensão de
referência alta do módulo ADC) e seus efeitos são os mesmos do jumper 3. O jumper 5 é
utilizado para selecionar a fonte do sinal SCIRXD (porta serial assíncrona de recepção de
dados da interface de comunicação serial) que é on chip. Caso esteja na posição 1-2, o sinal
que será encaminhado à UART será proveniente da serial. Caso a posição 2-3 seja
selecionada, o sinal deverá vir do pino 4 do conector de I/O
87
Pelo fato do DSK possuir o programa monitor para se comunicar com o PC, alguns
recursos do kit são requeridos. Estes recursos não devem de maneira alguma serem
utilizados pelos programas do usuário. Caso sejam utilizados, a capacidade de se debugar o
programa será prejudicada. Estes recursos, que representam as limitações do DSK, são os
seguintes:
• RAM de dados on chip (0x0060h - 0x007Eh) é utilizada para armazenar o
machine state;
• Os vetores de interrupção são realocados para a posição 0x8000h - 0x803Fh;
• Posições de memória entre 0x8040h - 0x8042h na RAM de programa são
utilizadas por comandos de I/O;
• A INT5 é utilizada para comunicação serial;
• O vetor TRAP (INT17) localizado na posição 0x0022h ;e usado por
breakpoints (pontos de parada) e para se avaliar passo a passo;
• O vetor de RESET localizado na posição 0x0000 é utilizado para se executar
o programa monitor no power up;
• O programa monitor é executado com interrupções habilitadas;
• O programa monitor desabilita o watchdo timer.
O manual do DSK apresenta como apêndice os esquemáticos referentes à todas as
partes do placa.
O pacote de softwares incluídos no kit DSK possibilitam o desenvolvimento e a
verificação do funcionamento dos programas relativos às aplicações desejadas. Este pacote
contém um elemento assemblador de códigos e um ambiente de debugger, utilizado para se
verificar todo o funcionamento dos programas. Por se tratar justamente de um pacote de
softwares, os programas contidos no mesmo não são considerados profissionais, mas
88
possibilitam atingir os resultados desejados. Inicialmente é comum que algumas dificuldades
apareçam mas com o passar do tempo e com a constante utilização destes ambientes estes
problemas serão superados. O assemblador consiste de um aplicativo DOS, não possuindo um
ambiente específico. Seus comandos são simples. Já o debugger apresenta um ambiente mais
trabalhado, consistindo de um aplicativo windows com vários recursos como a possibilidade
de criação de janelas gráficas, janela de visualização de código e posições de memória de
programa, janelas de visualização de memória específica (tanto de programa como de dados),
visualização dos registradores da CPU, possibilidade de inserção de marcas chamadas de
breakpoints para realização de execução em modo animado e a possibilidade de execução de
programas passo a passo.
89
13. ONDE E COMO PROGRAMAR
Esta seção tem por objetivo preparar os participantes a desenvolverem seus programas
para teste no kit DSK. Todas as informações contidas nesta seção se referem à utilização da
interface serial para comunicação com o kit. A utilização da interface JTAG traz diversos
benefícios que possibilitam uma programação mais completa. É importante dizer que este é
um nível extremamente básico, onde muitas definições não são sequer aplicadas. A
complexidade de desenvolvimento de softwares para o DSP em si pertence a um nível mais
elevado, requerendo um estudo mais aprofundado deste tipo de programação, o que não é o
objetivo deste curso. Contudo, a empresa possui diversos manuais que possuem informações
referentes à este nível de programação, e este curso fornece a base para que o futuro usuário
se familiarize o mais rápido possível com as definições apresentadas nos mesmos. O manual
mais completo com relação ao nível avançado de programação é o "Assembly Language Tools
- Users Guide".
13.1. ONDE PROGRAMAR
Para se desenvolver um software, utiliza-se qualquer ambiente que funcione como
editor de textos, como o edit do DOS, o wordpad e o bloco de notas do windows. Pode-se
desenvolver o programa nestes ambientes , mas o assemblador SD24XASM deve estar no
mesmo diretório que os programas desenvolvidos para podermos compilá-los.
Particularmente eu indico o uso do wordpad para desenvolvimento. A terminação do arquivo
a ser compilado deve ser .asm, se for .txt o arquivo não será compilado. Assim, ao salvar
determinado programa, salve com a extensão .asm. O seguinte comando inicia a compilação
do arquivo "xyz.asm" que deve ser digitado no prompt do dos:
90
C:\ diretório> sd24xasm -l xyz.asm
Na linha anterior, sd24xasm é o comando que invoca o assemblador. A opção -l pede
para ser gerado o arquivo .lst (listing file), pois na hora de carregar o programa no DSK, o
debugger irá reclamar, caso este tipo de arquivo não tenha sido gerado, e finalmente o
xyz.asm indica qual programa será compilado. Existem outras opções além da -l, mas não são
relevantes no momento.
Compilando-se o programa, iremos gerar um arquivo de mesmo nome com a
terminação .dsk, que é o tipo de arquivo válido para ser carregado no kit de desenvolvimento.
Note que enquanto não forem retirados os erros, o arquivo .dsk não é gerado. Uma vez que a
compilação foi bem sucedida, podemos carregar o programa através do software Code
Explorer, que constitui o ambiente de debugger do DSK. O arquivo tutorial fornece todas as
informações necessárias para se iniciar os experimentos no Code Explorer.
Algumas particularidades deste ambiente são:
• Possibilidade de visualização de qualquer posição das três memórias
existentes
• Possibilidade de se gerar gráficos, mas para isso os valores deverão estar
gravados de forma seqüencial na memória de dados
• Possibilidade de visualização dos registradores mais importantes da CPU
Com estes conhecimentos já é possível interagir com o ambiente do DSK para
desenvolvimento de softwares.
91
13.2. COMO PROGRAMAR
Esta seção trata de alguns métodos para se iniciar uma programação. Os itens que
serão apresentados tem por função sanar algumas possíveis dúvidas e dificuldades que
surgirão no início das atividades de programação.
13.2.1. As diretivas .include e .copy
Iniciamos os estudos com estas diretivas, pois são elas que nos permitem definir, antes
de mais nada, quem usaremos como arquivo "extra" no nosso programa. Por exemplo,
queremos realizar algumas manipulações com dados referentes a uma tabela. Sabemos que
para tal, o assemblador deve reconhecer esta tabela. Para não a inserirmos nas linhas de
código do programa, podemos dizer ao assemblador que esta é um arquivo separado, mas faz
parte do programa. Isto deve ser feito da seguinte forma, supondo o nome do arquivo como
tabela.txt:
.include "tabela.txt"
Desta forma, o assemblador irá buscar o referente arquivo (que deve estar no mesmo
diretório), e o incluirá automaticamente no seu programa. A diferença entre a diretiva .include
e a diretiva . copy é que a utilização da primeira acarreta na não inclusão em termos de
código, das linhas do arquivo a ser incluido no arquivo .lst, já com a .copy ocorre o contrário.
Um fato importante é que devemos sempre incluir o arquivo que define os endereços
de todos os registradores do F243, para podermos utilizar o endereçamento direto. Este
arquivo é o 24x.h. Por isso, a primeira linha dos nossos programas deverá ser :
.include "24x.h"
Dessa forma, poderemos utilizar o endereçamento direto através dos DP's, lembrando
que o DP fornece os 9 MSB's do endereço, e o operando fornece os 7 LSB's do mesmo. Isto
92
será importante para entendermos como é feita a definição de variáveis na memória de dados,
e como acessamos as mesmas.
13.2.2. As Diretivas .setsect e .sect
Esté tópico é muito importante, pelo fato de que não querermos que, por exemplo,
linhas de código referentes ao corpo do programa "invadam" a área reservada para a definição
de interrupções. Para isto, existe uma diretiva que realiza o particionamento da memória de
programa em diversas seções, que são então nomeadas conforme a vontade do usuário. Por
exemplo, para definirmos os vetores de interrupção, de forma que utilizemos as INT's 1, 2 e 3,
o fazemos da seguinte forma:
.setsect ".vectors",8000h .sect ".vectors" RSVECT B START ;reset = pulo para inicio INT1 B GISR_INT1 ;pulo para tratamento PASSAGEM0 INT2 B GISR_INT2 ;pulo para tratamento INVERSOR INT3 B GISR_INT3 ;pulo para tratamento PFC INT4 B PHANTOM ;demais interrupções são tratadas com ret INT5 B PHANTOM INT6 B PHANTOM
A diretiva .sect define quem será a seção corrente, ou seja, qual seção será assemblada
no momento. No exemplo anterior, na primeira linha definimos que a seção .vectors se inicia
na posição 8000h da memória de programa (conforme indicado no capítulo de interrupções).
Na linha seguinte, indicamos que a seção corrente é a própria .vectors. As demais linhas de
código são então assembladas dentro desta seção.
Desta forma, podemos definir seções em endereços diferentes, o que garante que não
haverá sobrescrição de códigos na memória de programa. Uma vez definido o início da seção,
poderemos mudar livremente de seção corrente através da diretiva .sect.
93
13.2.3. Como definir variáveis na memória
Uma das definições apresentadas pela bibliografia para atingirmos tal objetivo é a
diretiva .bss. A seção .bss é uma seção padrão do DSP, assim como as seções .text (onde
geralmente vai o programa) e a seção .data (onde geralmente estão constantes e variáveis
inicializadas). Porém, existem surpresas com relação à esta parte, onde infelizmente o kit não
suporta esta diretiva, se operado via porta serial. Por isso, devemos inicialmente definir,
em termos de projeto, uma seção especial na qual definiremos as variáveis com o valor do
endereço de memória que queremos alocar para as mesmas. Como o método de
endereçamento mais utilizado para o desenvolvimento de softwares é o endereçamento direto,
ao definirmos o valor das variáveis, devemos fazê-lo como sendo no máximo 7 bits úteis.
Note que estamos definindo valores que futuramente indicarão os 7 LSB's do endereço de
uma posição de memória. Isto é como definirmos ponteiros únicos para cada posição de
memória em cada página da mesma.
Considere o exemplo:
.setsect ".vars",300h _OFFSET .set 00h ;nosso ponteiro pela tabela _TABLE .set 01h ;guarda início da tabela _VOUT .set 02h ;guarda tensão de saída _SINEVAL .set 03h ;variável de manipulação de valores da tabela
Nos códigos acima, estamos inicialmente definindo que a seção de variáveis se inicia
na posição 300h, somente para lembrar que as variáveis estarão no DP 6 (a partir da 0300h da
memória de dados, pois esta área pode ser usada para tal). Logo após inicializamos as
variáveis em questão com os valores 00h, 01h, 02h e 03h. Na verdade, estas variáveis
94
guardam valores que futuramente apontarão para um endereço da memória de dados, através
do endereçamento direto.
Note que as variáveis são inicializadas com até 7 bits úteis, e esta inicialização é feita
através da diretiva .set. Esta diretiva possui a mesma função que a diretiva .equ, que relaciona
um valor constante qualquer com um símbolo. O símbolo pode ser utilizado no código
assembly, ao invés de se usar diretamente o valor. A restrições para se utilizar estas diretivas
é:
• O símbolo deve estar no campo de label (colado à margem esquerda do editor)
O usuário deve estar atento ao fato de que estamos definindo apenas valores, e sua
utilização será feita pelo endereçamento direto, por isso, ao se utilizar estas variáveis,
certifique -se que o data page foi definido corretamente nas linhas anteriores, senão o dado
poderá ser gravado em outra posição de memória, o que é indesejado. Por exemplo:
LDP #6 SACL _VOUT
A intenção das linhas anteriores é salvar o conteúdo do acumulador baixo na variável
_VOUT. Desta forma, setamos o DP como 6 ou (0…110)b e a próxima instrução indica que o
DSP deve salvar o conteúdo do ACCL na posição de memória apontada por _VOUT. Como
sabemos, o _VOUT foi inicializado com o valor 02h. Desta forma, o endereço se constitui da
seguinte forma:
DP = 000000110 ( 9 bits ) + _VOUT = 0000010 ( 7 bits )
Endereço = 0000001100000010 b = 302 h (16 bits )
95
Desta forma, estaremos salvando o ACCL na posição 302 h, que pode ser apontada
pela variável _VOUT aliada ao DP correto. Note que um erro no estabelecimento do DP pode
prejudicar totalmente o programa.
Porém, quando for possível utilizar a interface JTAG, estes problemas não aparecem
mais, e podemos utilizar livremente todas as diretivas do assembly da Texas, incluindo a .bss.
Esta diretiva define variáveis em uma seção chamada de bss, onde a instrução é
constituída da seguinte forma:
.bss _var, 5
O primeiro campo indica que a seção selecionada é a bss. A seguir deve constar o
nome da variável desejada, seguido então pela vírgula e em seguida pelo tamanho desejado
para esta variável em words (palavras de 16 bits).
13.2.4. Iniciando-se o programa em si
Tendo-se estabelecido todos as variáveis iniciais, bem como as interrupções que serão
utilizadas, podemos partir agora para o corpo do programa.
Este deve ser desenvolvido dentro da seção padrão .text, onde só é preciso definir o
início da área desejada para se carregar o mesmo na memória de programa. Considere o
seguinte exemplo:
.setsect ".text",2000h .text
96
CONSTANTES_PID: NOP _K0: LDP #6 LACC #32768*166/1000 SACL _K0 ;_K0 = 0.166 normalizado (dma) B inicio _Kn .int 32768*162/1000 K1: .int -32768*409/1000 ;_K1 = -0.439 normalizado (pma) K2: .int 32768*3185/10000 ;_K2 = 0.3185 normalizado (pma) K3: .int 32768*0000/100000 ;_K3 = 0 K4: .int 32768*9999/10000 ;_K4 = 0.9999 normalizado (pma)
Inicialmente informamos ao processador que a seção .text iniciará em 2000h. Em
seguida definimos a seção corrente como sendo a própria .text. A partir deste momento, todas
as linhas subseqüentes serão assembladas dentro desta seção. Note no exemplo a definição
das constantes PID, utilizando-se também os conceitos do capítulo referente às representações
numéricas.
Uma dica importante é se efetuar todo tipo de inicialização desejada no início desta
área, pois geralmente este é o momento para tal. Definições tardias podem acarretar em um
mau funcionamento do programa.
Desta forma já é possível se iniciar o desenvolvimento de programas complexos, onde
a base do esquema já foi apresentada, e o usuário deverá se concentrar em funções mais
complexas que as integrantes deste curso.
97
top related