PDA

View Full Version : USART TX Interrupt problem. (DT_INTS)



HenrikOlsson
- 16th August 2011, 12:05
Hello everyone,

I've got a bit of a problem getting my USART TX interrupt working correctly (using DT_INTS), something that I've done numerous times before. This is on a 18F25K20 (on the AMICUS 18 board) and here the piece of code I'm using as a base for testing:

DEFINE OSC 64
DEFINE LOADER_USED 1 ' We're using a bootloader.
DEFINE HSER_RCSTA 90h ' Enable serial port & continuous receive
DEFINE HSER_TXSTA 24h ' Enable transmit, BRGH = 1
DEFINE HSER_CLROERR 1 ' Clear overflow automatically
DEFINE HSER_SPBRG 138 ' 115200 Baud @ 64MHz, -0,08%

SPBRGH = 0
BAUDCON.3 = 1 ' Enable 16 bit baudrate generator

INCLUDE "DT_INTS-18.bas" ' Include Darrels interrupt engine.
INCLUDE "ReEnterPBP-18.bas" ' And the stub needed for interrupts in PBP

ASM ; Set up the USART transmit interrupt.
INT_LIST macro ; IntSource, Label, Type, ResetFlag?
INT_Handler TX_INT, _USART_TX, PBP, no
endm
INT_CREATE ; Creates the interrupt processor
ENDASM

String_1 VAR BYTE 50 ' Array to hold string.
TXPointer VAR BYTE ' Pointer into array

HSEROUT["Program start",13,13]

ArrayWrite String_1, ["This is the content of String_1",13,0]

'-------------------------------------------------------------------
HSEROUT["First test: "]
HSEROUT[STR String_1]
Pause 200
'-------------------------------------------------------------------

'-------------------------------------------------------------------
HSEROUT["Second test: "]
TxPointer = 0
While String_1[TxPointer] <> 0
HSEROUT[String_1[TXPointer]]
TxPointer = TxPointer + 1
WEND
Pause 200
'-------------------------------------------------------------------

'-------------------------------------------------------------------
HSEROUT["Third test: "]
TxPointer = 0
@ INT_ENABLE TX_INT
Pause 200
'-------------------------------------------------------------------

'-------------------------------------------------------------------
HSEROUT["Fourth test: "]
TxPointer = 0
While String_1[TxPointer] <> 0
HSEROUT[String_1[TXPointer]]
TxPointer = TxPointer + 1
WEND
Pause 200
'-------------------------------------------------------------------

END

'-- Interrupt service rotuine for USART TX Interrupt ---------------
USART_TX:
TXReg = String_1[TxPointer] ' Load character from array into USART TX register
If String_1[TxPointer] = 0 then ' If that character was a NULL we're done so we.....
@ INT_DISABLE TX_INT ; ...disable the any further USART TX interrupts.
ELSE ' If the character was not a CR we.....
TxPointer = TxPointer + 1 ' ...increase the pointer, prepare to send the next character.
ENDIF ' As soon as the TX-reg is empty the interrupt will fire again. (~1ms at 9600baud)
@ INT_RETURN

As you can see I load an array with a short string and then I send it out using various methods. This works exactly as I want, on the serial terminal I get the following, each time I reset the device:

Program start

First test: This is the content of String_1
Second test: This is the content of String_1
Third test: This is the content of String_1
Fourth test: This is the content of String_1

However, if I now increase the size of the array to 100 it messes up and I get this instead:

Program start

First test: This is the content of String_1
Second test: This is the content of String_1
Third test: TFourth test: T

As you can see something is now messed up and I don't understand what and why. The interrupt routine seems to disable the interrupt after the first character and then, what previously worked fine in Test2, no longer works either. As if the array got corrupted.

As a debug aid I then added a fifth output as follows:

HSEROUT[13, "Fifth test",13]
For TXPointer = 0 to 35
HSEROUT [DEC TXPointer,": ", DEC String_1[TXPointer],13]
NEXT
Pause 200

END

The output of this clearly shows why the interrupt routine (and the following WHILE-WEND routine) stops sending - there's now a NULL at location 1 in the array - the array has somehow gotten corrupted:

First test: This is the content of String_1
Second test: This is the content of String_1
Third test: TFourth test: T
Fifth test
0: 84
1: 0
2: 0
3: 115
4: 32
5: 133
6: 0
7: 32
8: 116
9: 104
10: 0

The 25K20 used here has 1536 bytes of RAM so I can't imagine it's running out of room - in which case I should've gotten a message about it not being able to fit the array, which I don't.

This was initially with 2.60A but I've tried with 3.01 and I get the same results.

I've tried declaring the array as various sizes. At 50 bytes everything works, so does 63 but at 64 bytes it "starts" to fall apart, the output then becomes:

First test: This is the content of String_1
Second test: This is the content of String_1
Third test: This is the content of String_1
`Fourth test: This is the content of String_1
`

What am I doing wrong here? Why is the ISR corrupting my array? I've got the ISR declared as type PBP so it's not that. What is that I'm not seeing here?

/Henrik.

amgen
- 16th August 2011, 12:47
Hi,
may need a different pointer for TX int if you are using that one for HSER also. I think they will get intertwined !?

don

HenrikOlsson
- 16th August 2011, 13:09
Thanks don,
I was actually trying some things with regards to your latest thread when I stumbled across this.

You have a good point. However, I don't think different pointers will make any difference in this case. Here's the reason(s) for my statement.

1) I have a Pause 500 after enabling the interrupt, that's more than enough to send the string out. This means that TXPointer is free to use when "test 4" begins.

2) If that was the case then the size of the array wouldn't matter. Note that I'm not changing the amount of data actually written to the array, I just change the declared size of it. 50 works, 100 doesn't.

3) When test 5 is executed it shows that the actuall content of the array is changed. I forgot to mention this is in first post but I initially used another pointer variable (not TXPointer) in Test5 and it gave the same result as when using TXPointer - ie, it shows that the array is corrupted.

/Henrik.

amgen
- 16th August 2011, 13:35
OK then,

This puts a byte at location 50 (dec) in ram


String_1 VAR BYTE 50 ' Array to hold string.


this puts array of 50 where PBasic puts it


String_1 VAR BYTE [50] ' Array to hold string.


this puts array of 50 at location $100, (100hex, 256 dec)


String_1 VAR BYTE [50] $100 ' Array to hold string.



At the bottom of the generated LIST file is a listing of the mem locations for ram and prog mem
there you can see the var's location and alotted space left between arrays.

5873

Don

HenrikOlsson
- 16th August 2011, 13:43
That's it, thank you!
It was all in the declaration, I had forgot the brackets!

Can't belive I didn't think of that - the number of times I've been there and changed the value and missed the missing brackets. Guess, since it worked with an imiginary lenght of 50 it was harder to see.

Thanks again!

/Henrik.

amgen
- 16th August 2011, 14:24
that will be $1 or cup of coffee or credit for my future dumb stuff

don

Dave
- 16th August 2011, 16:20
Henerik, Why are you using HSEROUT when you have the interrupt all setup?

HenrikOlsson
- 16th August 2011, 16:39
Because the interrupt messed up my array of data and the HSEROUT statements helped me show what was going on. Which turned out to be that I hadn't declared the array properly.

Dave
- 17th August 2011, 01:04
Yeah, I understand that but, Why don't you just load the array with your message and then enable the interrupt? You have the code there already.. The interrupt will disable it when the message is sent... I have used this methode for the last few years but not with the ARRAYREAD or ARRAYWRITE statements... Just loose the HSEROUT stuff.... THat way it's all done in the background...

HenrikOlsson
- 17th August 2011, 07:10
Dave,
That was the purpose all along and that is exactly what I did - but it didn't work, it just gave me garbage as you can see in my first post. So I added the HSEROUT statements to help debug the problem which, again, was my erronous array declaration. Now when teh problem is found and fixed the HSEROUT statements are gone.

The code isn't "production code" it's code to illustrate the problem I had with the interrupt routine corrupting my array.

/Henrik.

Dave
- 17th August 2011, 11:44
Henrik, Yes I understand now. However if you are going to use this routine:
'-- Interrupt service rotuine for USART TX Interrupt ---------------
USART_TX:
TXReg = String_1[TxPointer] ' Load character from array into USART TX register
If String_1[TxPointer] = 0 then ' If that character was a NULL we're done so we.....
@ INT_DISABLE TX_INT ; ...disable the any further USART TX interrupts.
ELSE ' If the character was not a CR we.....
TxPointer = TxPointer + 1 ' ...increase the pointer, prepare to send the next character.
ENDIF ' As soon as the TX-reg is empty the interrupt will fire again. (~1ms at 9600baud)
@ INT_RETURN

I would check for the end of the string before I send the a character, That way you won't be sending the null character from the end of the array. You will get an interrupt when the last character is sent and at that time you don't want to be sending any more, just disable the interrupt and leave.... just change the routine to read:

'-- Interrupt service rotuine for USART TX Interrupt ---------------
USART_TX:
If String_1[TxPointer] = 0 then ' If that character was a NULL we're done so we.....
@ INT_DISABLE TX_INT ; ...disable the any further USART TX interrupts.
ELSE ' If the character was not a CR we.....
TXReg = String_1[TxPointer] ' Load character from array into USART TX register
TxPointer = TxPointer + 1 ' ...increase the pointer, prepare to send the next character.
ENDIF ' As soon as the TX-reg is empty the interrupt will fire again. (~1ms at 9600baud)
@ INT_RETURN

HenrikOlsson
- 17th August 2011, 12:34
Hi Dave,
Good point! I cut and pasted the routine from a working program in which I used 13 as the string terminator - which I did want to send. With NULL as the terminator checking it first is of course better.

/Henrik.