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

[Solved] PIC24EP512 - Can a DMA transfer be paused?
Goto page Previous  1, 2, 3, 4  Next
 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
benoitstjean



Joined: 30 Oct 2007
Posts: 542
Location: Ottawa, Ontario, Canada

View user's profile Send private message

PostPosted: Wed Sep 18, 2019 3:45 pm     Reply with quote

Ok, thanks a lot guys.

I don't know why, all of a sudden I don't get notifications when a reply is posted. Actually, I got 1 reply out of all that are here. Perhaps it's the CCS mail server having an issue?

Who knows!

Thanks for all and I will keep all this in the back of my mind. It's difficult to tell exactly what happens and I can't reproduce the problem at will therefore implementing a solution for something that is not a problem may cause other problems!

Anyhow, I'll have a closer look tomorrow morning at your explanations.

Ben
benoitstjean



Joined: 30 Oct 2007
Posts: 542
Location: Ottawa, Ontario, Canada

View user's profile Send private message

PostPosted: Fri Sep 20, 2019 7:00 am     Reply with quote

Guys,

So, back to your suggestions regarding the read of characters in a loop...

Fair enough, the buffer can hold up to 4 characters. Note here that the characters can be anything from 0x00 to 0xFF.

You say I should "loop 'while' data is available".

Upon jumping in the #INT_RDA interrupt, this is what I am currently doing:

UART.RxChar = (unsigned char) fgetc( MODEM_SERIAL );

If I change so that 'RxChar' is a 4-byte wide array rather than a single character, what is my loop exit condition in a sense that if I read fgetc() 4 times, as far as I know, it won't return a code saying the buffer is empty... So what do I need to check exactly?

Some direct registers like U1STA?

[EDIT] I guess there's something else I'm missing... looking at the UxRXREG in the MCP docs, that's just for a single byte.... so how do I know how many bytes are in the buffer but where is the buffer for the other bytes? Sorry if I seem confused but I am!

[EDIT 2] A few minutes after writing this message, I got a UART error and when it jumped to the error interrupt, the value of U1STA is 0x0510:

Bit 4: RIDLE = 1 (Receiver IDLE)
Bits 8: TRMT = 1 (Transmit Shift Register is Empty and transmit buffer is empty)
Bit 10: UTXEN = 1 (UART1 transmitter enabled)

[EDIT 3] Ok, so I may have found the culprit but not sure *exactly* why it happens. In the MCP document DS70582D-page 17-18, it states:

The user application needs to enable the corresponding Interrupt Enable Control bit (UxERIE) in the IEC4 register to go to the corresponding interrupt vector location.

I can't seem to find any details on the UxERIE register in that document nor in the main datasheet for the part.

What I'm seeing with my logic analyzer data captures is that my PC application sends an "are you alive" packet to my device. When the device receives that message, it responds with the exact same message.

On occasion, my device will transmit two other packets of data (based on a periodic timer, e.g. every minute) to my application and it seems that when I get the #INT_UART1E, it's because immediately after the transmission of the second packet, my application sends the "are you alive" packet to which my device does not seem to respond because the following packet is another periodic packet for another message. So I would guess that there's some sort of a bus collision here therefore I am now realizing that the #INT_UART1E is not just for RX but for TX as well...

So I think all of this has to do exactly with the way the characters are received and how the #INT_RDA interrupt is handled etc which goes back to my initial question at the very top of this message: what is my loop condition to exit when reading 4 characters with fgetc() given that I have no idea how many characters are in the buffers and not sure exactly how to handle this even at the root register level...

Ben
newguy



Joined: 24 Jun 2004
Posts: 1899

View user's profile Send private message

PostPosted: Fri Sep 20, 2019 11:03 am     Reply with quote

kbhit()....test for it.
benoitstjean



Joined: 30 Oct 2007
Posts: 542
Location: Ottawa, Ontario, Canada

View user's profile Send private message

PostPosted: Fri Sep 20, 2019 11:12 am     Reply with quote

Ohhh.... geez, didn't realize that!

So rather than grabbing ONE character, just loop like this:
Code:

unsigned int8 Index = 0;

while( kbhit() == TRUE )
{
   UART.RxChar[Index] = (unsigned char) fgetc( MODEM_SERIAL );
   Index ++;
}

So if it grabs 2 characters, then index will be 2.
benoitstjean



Joined: 30 Oct 2007
Posts: 542
Location: Ottawa, Ontario, Canada

View user's profile Send private message

PostPosted: Fri Sep 20, 2019 11:28 am     Reply with quote

Hmmm....

At the moment, U1STA --> URXISEL is set to 00. This means that I have an interrupt after EACH received character.

I'll have to figure something out because this is where it gets more complicated.

When the device boots-up, it is set to run in normal UART mode, straight raw characters back and forth with the modem.

Then when the modem is ON, it gets initialized first with a few AT commands but then, the multiplexer protocol is enabled on the modem and from that point-on, as characters arrive from the UART, they must analyze characters immediately in order to properly change the state machine.

UART multiplexing specs: https://www.3gpp.org/ftp/tsg_t/TSG_T/TSGT_04/Docs/PDFs/TP-99119.pdf

I find that the fact that they used the same framing character 0xF9 for the start of frame and end of frame complicates things.

I haven't figured it out (or thought it out) yet but I can't just accumulate incoming data and parse it later because I don't know what I'm receiving.

The MUX protocol calls for this type of packet (example):

0xF9 0x0F 0xFF 0x1F PL CS 0xF9 where:

0xF9 is start of frame
0x0F is used as a channel ID (there are many channel ID's and the ID's change depending on if it's sending or receiving)
0xFF is the type of frame (there are many types of frame)
0x1F is the payload length
PL is the actual payload of "length" bytes
CS is the checksum
0xF9 is end of frame

So as data bytes arrive, I have a whole state machine that checks each byte immediately when it arrives and does whatever it has to do with it and if one byte is off, then the frame is discarded and the whole process restarts.

If I sample data by chunks of unknown length from 1-4 bytes, that can make the code quite more complex, no?

I'll have to analyze this more in details because that seems complicated.

Ben
Ttelmah



Joined: 11 Mar 2010
Posts: 19195

View user's profile Send private message

PostPosted: Fri Sep 20, 2019 12:17 pm     Reply with quote

Just because the interrupt occurs for each character, does not mean there is
only one character when you get into the interrupt. Depending on any delays
there could be several characters waiiting.
You are thinking incorrectly by thinking that F9 is a start or stop. You
simply always treat a F9 as a start. You then read the next bytes as the
address and if it is a valid address proceed to process the frame. If another
F9 arrives you restart.
The frame is accepted when complete with valid checksum.
The unit can send "F9 frame F9 frame F9", or "F9 frame F9 pause F9 frame
F9".
The 'end' F9 can be the start of the next frame.
benoitstjean



Joined: 30 Oct 2007
Posts: 542
Location: Ottawa, Ontario, Canada

View user's profile Send private message

PostPosted: Fri Sep 20, 2019 12:25 pm     Reply with quote

Hmmm... F9 is used as a start AND stop of the packet.

It looks like this:

F9 ..... F9F9 ..... F9

Not F9..... F9...... F9.....

Two consecutive F9's means an end and a start.

I'll have to think this out for a while because this part gave me a lot of grief when I started this project.

Ben
Ttelmah



Joined: 11 Mar 2010
Posts: 19195

View user's profile Send private message

PostPosted: Fri Sep 20, 2019 1:24 pm     Reply with quote

No. If you read the data sheet it specifically says that the second F9
can be the start of the next packet. There can be one or two between
packets. So it can be F9..... F9...... F9.....
This may well explain why you have issues....
benoitstjean



Joined: 30 Oct 2007
Posts: 542
Location: Ottawa, Ontario, Canada

View user's profile Send private message

PostPosted: Fri Sep 20, 2019 1:59 pm     Reply with quote

Ok, maybe I didn't explain myself well.

The multiplexer code has been working for years and that is not the problem.

If I was to send an invalid packet, the modem would return F9 F9 F9 F9 to which I have to reply F9 F9 F9 F9. That does happen on very rare occasions and it always recovers.

And I've never encountered a single time where a packet from the modem contained only one F9 - all packets have always started with F9 and ended with F9 (otherwise my multiplexer parsing code would have not worked, guaranteed).

What I am seeing here is the odd time where all of a sudden I get an INT_UART1E error interrupt. But I think this is good for both TX and RX, correct?

I'll investigate this more on Monday when I get back at the office.
benoitstjean



Joined: 30 Oct 2007
Posts: 542
Location: Ottawa, Ontario, Canada

View user's profile Send private message

PostPosted: Tue Sep 24, 2019 11:30 am     Reply with quote

Ok I think I know what is happening but I'm not sure how to fix it for now other than patching the thing but I'd like to fix it, not patch it.

INT_UART1E error interrupt occurs due to a race condition between a periodic 10-second timer which, when expired, transmits a packet containing sensor data to the UART TX DMA channel at the same time that the MCU is trying to send something else on the same UART TX DMA.

Back up a bit, I first receive on the MCU's UART RX pin (tied to the modem) an 'alive' packet from a remote application.

Then, when that packet is received by the MCU, in normal conditions, immediately following the reception of the 'alive' packet, an 'alive' packet is sent back out to the remote (through the UART TX DMA channel).... it acts as a handshaking between my circuit and the application:

(PC) Alive, you? --> (MCU) Alive, you? --> (PC) Alive, you? --> (MCU) Alive, you? ... and so on... This occurs around every 30 seconds.


What happens is that the modem transmits the 'alive' packet to the MCU but at the same time, as it attempts to respond with an 'alive' packet back, instead, the timer expires at that exact time and sends the sensor data packet... so two packets are somehow sent at the same time which generates an error. Shouldn't happen, explanation further.

So, I soldered a wire on a spare pin (59) on the MCU and when the interrupt occurs, I toggle that pin hi-lo and this is what my logic analyser triggers-on -- that pin change -- therefore I see 1.25 seconds of pre-buffered data, the event, then I let it go a few seconds then stop.

When I look at the analyzed data, I clearly see the received packet (modem to MCU), then I see the MCU pin toggle then I see the sensor data packet, which is wrong, because I should see the 'alive' packet transmission then the sensor packet transmission.... but it's not what happens, instead, I get a transmission collision which generates an error interrupt.

The only thing I have to figure-out is why that happens because of the following:

I have a transmit queue and a receive queue. The queues are structures with elements and I have a 50-deep array of each structure. Here the problem is with the tx queue.

I have an 'in' index and an 'out' index. The data to transmit based on certain events is stored in the tx queue at the 'in' position and they just add-up as the events occur. The tx queue for output is processed in the main() in an infinite loop when certain conditions are met. The tx queue is checked for new data to process and when it can process data, reads the tx queue at the 'out' position and processes the data from there.

The only time I should see data with the logic analyzer on the TX line is when it has been properly extracted from the queue, packetized and sent to the DMA memory block.

This all works nice and well, even when I am sending real-time 64kbps data, except for that one particular situation where the collision occurs and causes the error interrupt. But I don't understand how that happens because the tx queue cannot be processed until the DMA transfer is fully completed.

I'll go over the code again to see how it can even attempt to send two packets one after the other because that should not even be possible.

So my solution is to make the timer causing the problem expire at like 11 seconds rather than 10 seconds. But that might just offset the problem to something else. I'd rather fix it than patch it.

Ben
Ttelmah



Joined: 11 Mar 2010
Posts: 19195

View user's profile Send private message

PostPosted: Tue Sep 24, 2019 11:53 am     Reply with quote

Disable the timer interrupt while data is being transmitted.
Re-enable it afterwards. At this point the flag will be set, and the timer
data packet will be sent.
benoitstjean



Joined: 30 Oct 2007
Posts: 542
Location: Ottawa, Ontario, Canada

View user's profile Send private message

PostPosted: Tue Sep 24, 2019 12:01 pm     Reply with quote

Hmmm... I'm just afraid that something happens and fails to restart the interrupt...

Perhaps I could disable it when data is transmitted as long as it's not the realtime data (64kbps data) because.

The only other thing is that disabling the timer during a transmission may offset the timing of everything. I have _lots_ of timeouts, counters and delays... by 'delay' I don't mean like delay_ms(xxx) but rather a counter that delays something therefore on each timer interrupt, a counter is increased and when it reaches a certain count, it then executes a command.

I'll explore that avenue and report back.

Thanks.

[EDIT] Actually, I don't want to do that because I have, believe it or not, a timer that is started when the DMA transfer starts and if I don't get for whatever reason the #INT_DMA0 or #INT_DMAERR interrupts, that timer will expire and mean that the DMA transfer timed-out... unless there's a cleaner way to do that but it served its purpose a few times...
Ttelmah



Joined: 11 Mar 2010
Posts: 19195

View user's profile Send private message

PostPosted: Tue Sep 24, 2019 12:49 pm     Reply with quote

Why?
Each different timer has it's own interrupt. You only need to disable the one
that triggers the transfer.
If you are worried it may not get reenabled, simply have a flag that is set
when a transfer is occurring, and in you main code test if this is 'off' and
when it is reenable the interrupt.
Shifting the timing reduces the probability of a clash, but it will still occur.
You need to have a physical interlock, either by disabling the interrupt that
can cause this, or by adding a semaphore to block the second transmission
if another is already occurring.
benoitstjean



Joined: 30 Oct 2007
Posts: 542
Location: Ottawa, Ontario, Canada

View user's profile Send private message

PostPosted: Tue Sep 24, 2019 1:30 pm     Reply with quote

Tough to explain all of this, what I'm doing and why it's done this way. I have more timers and counter than the available number of timers on the MCU. So I had to use other means. However, I guess I could spread the timer load onto different PIC timers. I can't go into too much details about the circuit but there's a lot of stuff going-on at the same time.

I think now what I'm chasing is less that interrupt but more the DMA side which in return may solve the interrupt issue. I think it's all related.

Data is transmitted using the DMA channel.

Sometimes I may get the #INT_DMAERR and then it's stuck there in a loop just jumping in #INT_DMAERR until the MCU watchdog kicks-in. So that's one problem.

The code is written in a way that the data in the TX queue is sent in timeslices, sort of like a TDM bus so that the TX data is sent at regular interval out the DMA.

The problem is that, when I look at the data with my analyzer, all is fine but for some reason, after a few seconds of streaming the 64kbps data (it's PCM audio), all of a sudden the data stutters on my PC then if I stop the analyzer and look at the data, the 'good' audio is nice and clean where you can see each packet sent individually (about 11.2ms each) followed by an approximate 4.8ms between each packet.

Then when it starts to stutter on my PC, if I stop the the analyzer and look at the data, then there's no more gap between the packets and it's just one looooong chunk of data. It's all packetized fine and seems all there but something makes that there's no more gap between the packets and it's litterally one packet after another, the last F9 frame byte appears immediately followed by the F9 frame by of the next packet.

So instead of:

F9{packet here}F9 <4.8ms gap> F9{packet here}F9 <4.8ms gap> F9{packet here}F9

I see this:

F9{packet here}F9F9{packet here}F9F9{packet here}F9

I'll continue my research and try to figure-out what in the world is going-on because it should always be seen as packets followed by gaps like the first example above.

I'll keep posting.
Ttelmah



Joined: 11 Mar 2010
Posts: 19195

View user's profile Send private message

PostPosted: Tue Sep 24, 2019 1:40 pm     Reply with quote

If you are using a timer for multiple things, then simply add a flag to the part
that allows the extra transmission, and turn this flag off when the other
packet it being sent - so a 'semaphore' to allow the transmission.
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, 3, 4  Next
Page 2 of 4

 
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