Autor Tema: DMA en dsPIC33F, ¡ya funciona pero...!  (Leído 5925 veces)

0 Usuarios y 1 Visitante están viendo este tema.

Desconectado Nocturno

  • Administrador
  • DsPIC33
  • *******
  • Mensajes: 18269
    • MicroPIC
DMA en dsPIC33F, ¡ya funciona pero...!
« en: 07 de Enero de 2007, 17:14:03 »
Ya veo volar bytes en la DMA de mi dsPIC33F, aunque hay una funcionalidad que no consigo y me gustaría comentarlo por si alguien puede ayudarme.

Primero os hago una pequeña introducción de mi aplicación. Se trata de una comunicación SPI entrante en la que mi dsPIC33F actúa como slave y que se vuelca directamente en la DMA.

Para ello, he configurado el SPI y la DMA tal como sigue:

Código: [Seleccionar]
void ConfigSlaveSPI()   {

SPI1CON1bits.MSTEN=0; // modo slave
SPI1CON1bits.SMP=0; // debe ser 0 en modo slave
SPI1CON1bits.CKE=0; // el dato aparece al pasar de idle a activo
SPI1CON1bits.CKP=0; // idle es nivel bajo; activo es nivel alto
SPI1CON1bits.SSEN=0; // el pin /SSEN no se utiliza para modo esclavo
SPI1STATbits.SPIROV=0; // elimina errores de overflow
SPI1CON2=0; // Nada de Framed SPI
SPI1CON1bits.DISSDO=1; // El pin SDO está disponible para otros usos
SPI1CON1bits.MODE16=1; // Modo de 16 bits

SPI1STATbits.SPIEN=1; // activa módulo SPI
}

 void cfgDMA1SPIRx(void)
{
DMA1CONbits.SIZE=0; // transferencia de words completas
DMA1CONbits.DIR=0;  // del periférico al DMA
DMA1CONbits.HALF=0; // levanta la interrupción cuando termine la palabra
DMA1CONbits.MODE=2; // modo continuo y con ping-pong

DMA1REQ = 0x00A; // Selección de la IRQ10

DMA1STA= __builtin_dmaoffset(Spi1RxBuffA);
DMA1STB= __builtin_dmaoffset(Spi1RxBuffB);

DMA1PAD = (volatile unsigned int) &SPI1BUF; // puntero a la recepción del dato SPI

DMA1CNT = DMA_BUFFER-1; // se recibirán 15+1=16 registros en memoria

IFS0bits.DMA1IF  = 0; // Clear DMA interrupt
IEC0bits.DMA1IE  = 1; // Enable DMA interrupt
IPC3bits.DMA1IP=10; // Prioridad 10
DMA1CONbits.CHEN = 1; // Enable DMA Channel

}


Tras ejecutar estas dos funciones, empiezo a recibir words sobre la memoria DMA a través del periférico SPI, y me levanta una interrupción cada 16 words recibidas, que puedo leer con gran facilidad en los arrays Spi1RxBuffA y Spi1RxBuffB (como está en modo ping-pong una lectura se hace de un array y la siguiente del otro).

Código: [Seleccionar]
void __attribute__((__interrupt__)) _DMA1Interrupt(void)
{
if(RxDmaBuffer == 0)
ProcesaSPIRxSamples(Spi1RxBuffA);
elseSpi1RxBuffA
ProcesaSPIRxSamples(Spi1RxBuffB);
RxDmaBuffer ^= 1;
    IFS0bits.DMA1IF = 0;
}

Pues bien, ahora viene mi duda. Tal y como tengo configurado el DMA, sólo levanta la interrupción cuando se han recibido 16 words, pero habrá momentos en los que la transmisión haya finalizado con una cantidad inferior.
Si por ejemplo sólo recibo 4 words, ¿cómo puedo hacer que el DMA levante la interrupción tras un momento de pausa sin recibir nada?

En caso que eso no se pueda realizar, siempre puedo ponerme a leer el array desde cualquier parte del programa, lo cual también me sirve, pero ¿cómo puedo saber cuántos words se han leído por el DMA?

Agradeceré cualquier ayuda.

Desconectado Sispic

  • Moderador Local
  • PIC24H
  • *****
  • Mensajes: 1677
    • winpic800
Re: DMA en dsPIC33F, ¡ya funciona pero...!
« Respuesta #1 en: 08 de Enero de 2007, 06:37:14 »
my opinion :

El Master deve mandar , el Esclavo ovedecer .
Asi que Master , como no me digas lo que tengo que hacer  lo tienes claro .

Se podria utilizar DMA1CNT variable . (No se si es este el que determina el tamaño a recivir)

Este tamaño lo podria calcular el Esclavo segun el previo comando que reciva  y conocido por los dos ó que sea el Master quien se lo diga directamente .

Por defecto DMA1CNT = TAMAÑO_COMANDO // por ejemplo 2 words
En cuanto el Esclavo reciva previo comando y sepa lo que tiene que hacer maneja DMA1CNT segun le convenga .

Se podrian usar 2 registros y alguna banderilla  en cuanto el Esclavo ya sepa lo que se le  avecina .

PAQUETES_COMPLETOS = TOTAL_A_RECIVIR / DMA_BUFFER;
PICO = TOTAL_A_RECIVIR mod DMA_BUFFER;     

void __attribute__((__interrupt__)) _DMA1Interrupt(void)


if PAQUETES_COMPLETOS--  <> 0   DMA1CNT = DMA_BUFFER else DMA1CNT = PICO

Es solo para hacerme entender y una posible manera de hacerlo .

tambien SSEN para el Master para que sepa en todo momenteo si el Esclavo da avasto que seguramente cobra por horas  :D.



Desconectado Darukur

  • Colaborador
  • PIC18
  • *****
  • Mensajes: 464
    • Informacion, recursos y ejemplos para desarrollos con microcontroladores
Re: DMA en dsPIC33F, ¡ya funciona pero...!
« Respuesta #2 en: 10 de Enero de 2007, 08:34:06 »
Estuve viendo lo mismo, hasta con la USART de los DSPIC/PIC24.
Si lo pongo en interrupcion cuando se llene el buffer (4 words), no produce interrupcion hasta no completar el buffer con lo que se pierde la comodidad de interrucion cada 4 words por el inconveniente de analizar en otro lugar si hay algun dato, con lo que se genera latencia.
En fin solo lo uso en transmision (cargo todo lo posible el buffer y espero interrupcion cuando se vacie) para recepcion son mas las molestias que los beneficios.
El que no sabe lo que busca no entiende lo que encuentra.
Mi Pagina Web:  http://www.sistemasembebidos.com.ar
Mi foro:             http://www.sistemasembebidos.com.ar/foro/

Desconectado Nocturno

  • Administrador
  • DsPIC33
  • *******
  • Mensajes: 18269
    • MicroPIC
Re: DMA en dsPIC33F, ¡ya funciona pero...!
« Respuesta #3 en: 13 de Enero de 2007, 03:25:46 »
Finalmente lo he conseguido gestionando de manera dinámica el tamaño del buffer que gestiona el DMA, de manera parecida a como sugería el maestro Sisco.

Aquí dejo el código:

Código: [Seleccionar]
void ProcesaSPIRxSamples(unsigned int Recibido[])
{
/*
El primer Word que se recibe tiene la siguiente estructura
CCCC SSSS SSSS SSSS
donde CCCC es el código de un comando
y SSSS SSSS SSSS es el Sufijo

Hay tres tipos de comandos:
a) Comandos que no necesitan más información, toda va en el Sufijo: 0..3
b) Comandos que necesitan la información del sufijo y sólo un word adicional: 4..8
c) Comandos con nº de datos variable. Este valor "n" va en el sufijo: 9..15
*/

if (WordsPorRecibir==0) { // Si no había nada pendiente sólo se recibe 1 word, el comando
Comando=Recibido[0]>>12;
Sufijo=Recibido[0] & 0xFFF;
NuevaEjecucion=1;
if (Comando<4) { // comandos sin datos adicionales
WordsPorRecibir=0;
ProcesaComando (Recibido);}
else
if (Comando<8) // comandos que necesitan un dato
WordsPorRecibir=1;
else // comandos de longitud variable
WordsPorRecibir=Sufijo;
if (WordsPorRecibir>DMA_BUFFER_MAXIMO)
DMA_BUFFER=DMA_BUFFER_MAXIMO;
else
if (WordsPorRecibir==0)
DMA_BUFFER=1;
else
DMA_BUFFER=WordsPorRecibir;
}
else { // Se ha recibido un paquete del tamaño de DMA_BUFFER
NuevaEjecucion=0;
ProcesaComando(Recibido);
WordsPorRecibir=WordsPorRecibir - DMA_BUFFER;
if (WordsPorRecibir>DMA_BUFFER_MAXIMO) // Si aún quedan más de las que caben
DMA_BUFFER=DMA_BUFFER_MAXIMO; // se recibirá el máximo
else {
DMA_BUFFER=WordsPorRecibir; // y si no las que queden
if (DMA_BUFFER==0) // Si hemos acabado
DMA_BUFFER=1;   // se deja preparado para recibir el próximo comando
}
}
DMA1CNT = DMA_BUFFER-1; // siempre se configura para uno menos
}

Desconectado rodstar

  • PIC10
  • *
  • Mensajes: 8
Re: DMA en dsPIC33F, ¡ya funciona pero...!
« Respuesta #4 en: 30 de Abril de 2011, 05:25:32 »
Nocturno
Para ese problema yo uso el modo "Pattern Match Termination" donde tu le especificas DCH0DAT=’\r’ lo que hace que cuando el caracter del string sea ’\r’ (en mi caso como fin de string) entonces el DMA channel 0 dispara un interrupt flag.

Lo bueno es que funciona de manera esplénida y soluciona mi problema, lo malo es que... es una funcionalidad de los PIC32, mi familia preferida :) y que suelo usar; pero al parecer no está en los dsPIC's, al menos yo no he encontrado algo equivalente o que se le parezca.

En mi proyecto actual debo bajar a un dsPIC33 (FJ128GP706A) y me encuentro con tu mismo problema.
En todo este tiempo, haz encontrado solución alguna para este problema??

Desconectado Nocturno

  • Administrador
  • DsPIC33
  • *******
  • Mensajes: 18269
    • MicroPIC
Re: DMA en dsPIC33F, ¡ya funciona pero...!
« Respuesta #5 en: 30 de Abril de 2011, 05:29:14 »
No volví a intentarlo, lo siento.

Desconectado saimon

  • PIC10
  • *
  • Mensajes: 11
Re: DMA en dsPIC33F, ¡ya funciona pero...!
« Respuesta #6 en: 02 de Septiembre de 2011, 13:58:53 »
Hola.

Necesito ayuda, no se si es porque las vacaciones me han dejado mal, pero estoy intentando trasmitir por la UART a partir de la DMA para dejar libre al micro. Lo tengo configurado de esta manera.

Código: [Seleccionar]
void cfgUART1()
{
U1BRG = BRGVAL; // BAUD Rate Setting for 4800

U1STAbits.UTXISEL0 = 0; // Interrupt after one TX Character is transmitted
U1STAbits.UTXISEL1 = 0;
U1STAbits.URXISEL  = 0; // Interrupt after one RX character is received

IEC0bits.U1TXIE = 0; // Enable UART TX Interrupt

U1MODEbits.STSEL = 0; // 1 Stop bit
U1MODEbits.PDSEL = 0; // No Parity, 8 data bits
U1MODEbits.ABAUD = 0; // Auto-Baud Disabled
U1MODEbits.BRGH = 0; // Low Speed mode

U1MODEbits.UARTEN = 1; // Enable UART
U1STAbits.UTXEN = 1; // Enable UART TX
U1MODEbits.RTSMD = 1; // Simplex Mode
U1MODEbits.UEN = 1; // U1CTS and U1RTS are enabled and used  

U1MODEbits.IREN = 0;// disable IrDA
U1STAbits.UTXINV = 0;
U1MODEbits.URXINV = 0;

IEC0bits.U1RXIE = 1;
IPC2bits.U1RXIP = 1;

CORCONbits.PSV = 1;

}

void cfgDMA1(int nvar)
{


DMA0CON = 0x2001; // One-Shot, Post-Increment, RAM-to-Peripheral
DMA0CNT = nvar; // n DMA requests
DMA0REQ = 0x800C; // Select UART1 Transmitter, manual mode
DMA0PAD = (volatile unsigned int) &U1TXREG;
DMA0STA = __builtin_dmaoffset(BufferA);
IFS0bits.DMA0IF = 0; // Clear DMA Interrupt Flag
IEC0bits.DMA0IE = 1; // Enable DMA interrupt

}


Lo quiero en modo manual de tal manera que quiero empezar a enviar datos cuando decida que es buen momento (para evitar posibles colisiones inesperadas). Por lo demás es básicamente lo que hay en los ejemplos del datasheet.

Despues me he creado una subrutina que es la encargada de enviar los datos.

Código: [Seleccionar]
void WriteBufferDMA1(char Data[40], int Size)
{

int DataCount;

for(DataCount = 0; DataCount < Size; DataCount++)
{
BufferA[DataCount]=Data[DataCount];
}
cfgDMA1(Size);
DMA0CONbits.CHEN=1;


}


Con esto paso mi texto al DMA y espero a que salga por pantalla. No me envia nada, sin embargo si recibe y si lo paso a la UART a pelo me funciona correctamente.
Alguien me puede echar una mano a ver que estoy haciendo tan mal.

Muchas gracias.
« Última modificación: 02 de Septiembre de 2011, 14:02:10 por saimon »

Desconectado saimon

  • PIC10
  • *
  • Mensajes: 11
Re: DMA en dsPIC33F, ¡ya funciona pero...!
« Respuesta #7 en: 05 de Septiembre de 2011, 09:57:33 »
Ya me funciona. me faltaba poner a 1 el bit DMA0REQbits.FORCE=1, por lo que mejorandolo queda:

Código: [Seleccionar]
void WriteBufferDMA1(char Data[40], int Size)
{

int DataCount;

for(DataCount = 0; DataCount < Size; DataCount++)
{
BufferA[DataCount]=Data[DataCount];
}
DMA0CNT = Size-1; // n DMA requests
DMA0CONbits.CHEN=1;
DMA0REQbits.FORCE=1;


}


Espero que a alguien le sea de ayuda.

Desconectado Nocturno

  • Administrador
  • DsPIC33
  • *******
  • Mensajes: 18269
    • MicroPIC
Re: DMA en dsPIC33F, ¡ya funciona pero...!
« Respuesta #8 en: 05 de Septiembre de 2011, 11:44:21 »
Gracias por compartir tu solución.


 

anything