CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to support@ccsinfo.com

PIC24 DMA help needed please [SOLVED]
Goto page Previous  1, 2
 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
guy



Joined: 21 Oct 2005
Posts: 291

View user's profile Send private message Visit poster's website

Update - code for compiler version 5.026, help???
PostPosted: Tue Aug 19, 2014 3:16 am     Reply with quote

problem: I'm using DMA with compiler v. 5.026 and PIC24FJ64GA308.
Good news: I solved a lot of issues (see below quick DMA guide...)
Bad news: The DMA interrupt routine only gets called once after the first DMA transaction. Even turning off the DMA module, clearing interrupts etc. doesn't help. Anyone has any ideas?

As for the part which does work:The documentation is not very clear so here is my version, which works well except the interrupt Razz

Code:
disable_interrupts(GLOBAL);
enable_interrupts( INT_TBE );
setup_dma(1,DMA_TRIGGER_TBE, DMA_BYTE);
dma_start(1, DMA_ONE_SHOT|DMA_FORCE_NOW|DMA_INC_SOURCE_ADDR,0x224,&txBuffer[0],cnt);

* cnt *doesn't* have to be decreased. It does represent actual number of trasnfers/characters sent.
* 0x224 is the destination address (U1TXREG). Adjust for other UARTs/peripherals.
* #BANK_DMA is not necessary for this compiler version and PIC. During startup the limit registers (DMAH & DMAL) get set to full address range, for better or for worse...
* Tip: DMA also seems to work without enabling any interrupts! If you *do* enable interrupts make sure to have a handler, even if it is empty. Otherwise the debugger will stop execution due to an unhandled interrupt. Example:
Code:
#INT_TBE
void tbe_isr() {
}

If you poll dma_status you will see 0x100 (DMA_REQUEST_INITIATED) immediately after dma_start. Then it reads 0, later 0x10 (DMA_HALF_DONE) and at the end 0x30 (DMA_HALF_DONE|DMA_DONE). If you plan on polling I suggest to poll for DMA_DONE bit:
Code:
while(!(dma_status()&DMA_DONE)) ;


Thanks for the guiding me in the right direction Cool
Ttelmah



Joined: 11 Mar 2010
Posts: 19255

View user's profile Send private message

PostPosted: Tue Aug 19, 2014 9:08 am     Reply with quote

DMA_ONE_SHOT, specifically disables the DMA channel when the transfer completes. It sets DMACNT to zero, so no further transfer will occur. The DMA_REPEATED option (or'ed in), tells it to reload the address, so it can be triggered again. You set or clear the CHEN bit to stop/start the transaction.

When using the DMA, the DMA controller receives the interrupt. The normal enable affects whether the CPU responds _as well_. You wouldn't normally want this, since the buffer will have already been written by the DMA controller.
guy



Joined: 21 Oct 2005
Posts: 291

View user's profile Send private message Visit poster's website

Solved
PostPosted: Tue Aug 19, 2014 9:28 am     Reply with quote

Quote:
DMA_ONE_SHOT, specifically disables the DMA channel when the transfer completes. It sets DMACNT to zero, so no further transfer will occur. The DMA_REPEATED option (or'ed in), tells it to reload the address, so it can be triggered again. You set or clear the CHEN bit to stop/start the transaction.

So DMA_ONE_SHOT is in fact what I need. I want to initiate a new, different-size transfer only when I have more data to send. By the way, I saw that CHEN is much more reliable than dma_status which I mentioned before.
Quote:
When using the DMA, the DMA controller receives the interrupt. The normal enable affects whether the CPU responds _as well_. You wouldn't normally want this, since the buffer will have already been written by the DMA controller.

Correct, of course. I only mentioned that it's not required since Microchip says you should enable the interrupt (5.2 Typical Setup).

Found it! Cool The DMA interrupt routine (not the trigger) was called only after the first transfer because the interrupt flags DONEIF, HALFIF don't get cleared (not even with clear_interrupt).
To fix this we need to clear them manually inside the interrupt routine or before the next transfer. Here is the complete code:

Code:
#include <24FJ64GA308.h>
#fuses XT,PR_PLL,BROWNOUT,WDT128,WDT,WPOSTS10,ICSP1
// 8MHz XT+4xPLL, WDT 2 sec nominal
#use delay(CLOCK=32000000)   // 8MHz*4PLL = 32MHz

#PIN_SELECT   U1RX   =PIN_B9 // from 232   conv from 5V to 3.3V
#PIN_SELECT   U1TX   =PIN_B8 // to 232  open drain!!

#use RS232(STREAM=R232, BAUD=9600, UART1, ERRORS) // VR-500 RS-485 bus

char buf[10];

/////////////////////////////

#INT_DMA0
void dma_isr() {
   // called when DMA is complete
   #WORD DMAINT0 = 0x38A   // DMA0 interrupt register
   
   fputc('*',R232);   // also UART1
   DMAINT0=0;   // clear interrupt flags, shut down DMA for now
}

/////////////////////////////

void DMAhandler() {
   #define U1TXREG 0x224   // uart1 transmit register address
   
   byte cnt;
   
   strcpy (buf, "Hi There");
   cnt=8;   // 8 characters
   
   setup_dma(0,DMA_TRIGGER_TBE, DMA_BYTE);
   // start DMA of 8 characters from buf to UART1 (AKA R232) :
   dma_start(0, DMA_ONE_SHOT|DMA_FORCE_NOW|DMA_INC_SOURCE_ADDR,U1TXREG,&buf[0],cnt);
}

//////////////////////////////

void main(void) {
   
   enable_interrupts(INT_DMA0);
   enable_interrupts(GLOBAL);
   
   DMAhandler();
   delay_ms(100);
   
   DMAhandler();
   delay_ms(100);
   
   DMAhandler();
   delay_ms(100);
   
   // output is Hi There*Hi There*Hi There*
   while(1) ;
}


Thanks everyone.
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Goto page Previous  1, 2
Page 2 of 2

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group