I've had a quick look through your code and it looks good on the face of it. (You obviously have a better idea about our chip than I gave you credit for initially. Sorry for that.) I think Richard's replying at the moment, so I thought I'd just offer a suggestion for the UART rather than dealing with the problem you raise.
To avoid receiving data when a glitch causes a start edge which isn't valid for a full bit duration, you could test for a logic 0 half way through the start bit. Nice to see you're properly testing the stop bit and waiting correctly for the stop bit when it's not present.
As I say I'll leave it for Richard to respond to the actual problem you have!
Errata Sheet for XS1-G4A-FB512-C4 0835 ES N65285.00
-
- XCore Addict
- Posts: 165
- Joined: Wed Feb 10, 2010 2:32 pm
-
- Respected Member
- Posts: 318
- Joined: Tue Dec 15, 2009 12:46 am
The mechanism for events on the XCore doesn't use memory in any way. There are no special memory locations you must avoid.va3ttn wrote:I remember the transputer having some special use for the memory location pointed to by Wptr,
and some other locations "at small negative offsets from Wptr".
With XS1, is it possible to induce an interference between timed input events
and TIMER events via some similar "special use" of memory locations?
-
- XCore Addict
- Posts: 165
- Joined: Wed Feb 10, 2010 2:32 pm
The actual time it takes from startup to failure might be interesting too. Particularly if its around 20s or around 40s.va3ttn wrote:Suddenly, UART receiver started to get blocked regularly, with quite predictable
average number of characters received before the blocking occurs.
-
- Member
- Posts: 12
- Joined: Sat Jul 03, 2010 1:46 pm
The blocking occurs exclusively when receiving characters.Could you clarify exactly what you mean by gets blocked?
Do you stop receiving characters or do you just miss some?
With no characters arriving, everything would stay OK, even overnight.
When the "thing" happens, RXhandler waits indefinitely
for timed input event (sampling a data bit in the middle).
It is usually found waiting to sample the first data bit (RXstate = 1),
but is occasionally found waiting for the second or third one.
Once it misses, it hangs forever.
It can be brought back to life by TIMERhandler
detecting the blocked state and then setting RXstate to 10
(wait for high level) and configuring the input port to wait
for the high level on the pin. Receiver then runs just like
it's restarted, and blocks again after receiving some number of characters.
Yes.Do the TIMERhandler events continue to fire?
I did so as described in comments just in front of the RXhandler.I would suggest using xrun xgdb to read the register state of the thread and also read the data in the RXRecord after it becomes blocked to see if this reveals anything. The pc of the thread and the current RXState would be of particular interest.
PC stays entirely within TIMERhandler.
-
- XCore Expert
- Posts: 844
- Joined: Sun Jul 11, 2010 1:31 am
Maybe you shouldn't set the timer condition to AFTER? I reckon AFTER will set the
event active every cycle in your timer event handler, until the "setd", an as far as I
can see, the "setd" will not clear it.
The documentation doesn't really describe this stuff much. It would be great if
the "xs1 arch" doc had pseudocode for how the ports and timers etc. behave.
event active every cycle in your timer event handler, until the "setd", an as far as I
can see, the "setd" will not clear it.
The documentation doesn't really describe this stuff much. It would be great if
the "xs1 arch" doc had pseudocode for how the ports and timers etc. behave.
-
- Member
- Posts: 12
- Joined: Sat Jul 03, 2010 1:46 pm
Well, AFTER and NONE are the only options applicable to timers.segher wrote:Maybe you shouldn't set the timer condition to AFTER?
Timer seems to run correctly, as verified both in the simulator
and observing pulses generated by the timer handler.
Anyway, timer's due time gets advanced immediately after
timer event recognition, and before re-enabling events globally by WAITEU.
-
- Member
- Posts: 12
- Joined: Sat Jul 03, 2010 1:46 pm
I've managed to reproduce the problem in 10.4 Simulator.
Proceed as follows.
1. Create an empty XC1 project, add the attached MAIN.S file and build.
The file is the same as above, plus an additional thread on the same core
to generate square waves with 11.52 kHz frequency. One period of the square
wave stands for one byte of 0xf0 at 115,200 bps (including start and stop bits).
2. Prepare a simulation as shown on Figures 1 and 2.
That is, run for 200,000 cycles, capture the trace,
connect pin XS1_PORT_1J to XS1_PORT_1I (core 0).
3. Run the simulation.
4. Open the ".vcd" file.
Select signals as shown on Figure 3.
Zoom Fit. Notice the cycle 141764 at 350.0 us.
Look at port 1I (UART RX input).
Its timeReg changes to 8912.
5. Zoom in around this point until something like Figure 4 appears.
The corresponding part of the trace file is also shown.
6. In cycle 141759 Timer0 increments to 8a6f, reaching the value set in line 1979 of the trace.
The timer event is recognized in cycle 141767 and TIMERhandler execution starts in cycle 141775.
7. In the meanwhile, the input port timer increments to 8911, reaching the value set in line 1959 of the trace.
THIS TIMED INPUT EVENT IS LOST FOREVER, as can be evidenced by scrolling the trace file and the waveform window.
8. RXhandler blocks indefinitely, and TIMERhandler continues to run.
Three bytes were received correctly, and RXhandler was blocked
waiting to sample the stop bit of the fourth byte (RXstate was set to 9 in line 1954 of the trace).
9. In the assembly file, line 71 "ldc r2, 800" can be changed to "ldc r2, 868",
and RXhandler will get blocked much faster, only 30,000 cycles need to be simulated.
I hope that some workaround is possible, so I won't have to scrap
my A4-sized four layer board hosting 2 XC-1 modules, Figure 5
Proceed as follows.
1. Create an empty XC1 project, add the attached MAIN.S file and build.
The file is the same as above, plus an additional thread on the same core
to generate square waves with 11.52 kHz frequency. One period of the square
wave stands for one byte of 0xf0 at 115,200 bps (including start and stop bits).
2. Prepare a simulation as shown on Figures 1 and 2.
That is, run for 200,000 cycles, capture the trace,
connect pin XS1_PORT_1J to XS1_PORT_1I (core 0).
3. Run the simulation.
4. Open the ".vcd" file.
Select signals as shown on Figure 3.
Zoom Fit. Notice the cycle 141764 at 350.0 us.
Look at port 1I (UART RX input).
Its timeReg changes to 8912.
5. Zoom in around this point until something like Figure 4 appears.
The corresponding part of the trace file is also shown.
6. In cycle 141759 Timer0 increments to 8a6f, reaching the value set in line 1979 of the trace.
The timer event is recognized in cycle 141767 and TIMERhandler execution starts in cycle 141775.
7. In the meanwhile, the input port timer increments to 8911, reaching the value set in line 1959 of the trace.
THIS TIMED INPUT EVENT IS LOST FOREVER, as can be evidenced by scrolling the trace file and the waveform window.
8. RXhandler blocks indefinitely, and TIMERhandler continues to run.
Three bytes were received correctly, and RXhandler was blocked
waiting to sample the stop bit of the fourth byte (RXstate was set to 9 in line 1954 of the trace).
9. In the assembly file, line 71 "ldc r2, 800" can be changed to "ldc r2, 868",
and RXhandler will get blocked much faster, only 30,000 cycles need to be simulated.
I hope that some workaround is possible, so I won't have to scrap
my A4-sized four layer board hosting 2 XC-1 modules, Figure 5
You do not have the required permissions to view the files attached to this post.
Last edited by va3ttn on Fri Jul 23, 2010 11:34 am, edited 2 times in total.
-
- Member
- Posts: 12
- Joined: Sat Jul 03, 2010 1:46 pm
Rest of the files.
Code: Select all
.text
.file "main.S"
.align 2
#include <xs1b_user.h>
.globl main
.globl main.nstackwords
.linkset main.nstackwords, 0
// use of registers
// r0..r3 arguments, return values saved by caller
// r4..r10 scratch saved by subroutine
// r11 scratch saved by caller
// cp constant pointer saved by subroutine
// dp data pointer saved by subroutine
// sp stack pointer saved by subroutine
// lr link register saved by subroutine
// RX record layout:
// 0 RXstate
// 1 portaddress
// 2 porttime
// 3 del10bit
// 4 del15bit
// 5 shiftreg
// 6 datareg
// 7 dataready
// RXstate encoding:
// 0 wait for start bit
// 1..8 sample data bits
// 9 sample stop bit
// 10 wait for high level (initial state)
RXrecord:
.int 10 // RXstate = waithighlevel
.int 0x10a00 // portID = 1I
.int 0 // porttime
.int 868 // del10bit (115200 bps)
.int 1302 // del15bit
.int 0 // shiftreg
.int 0 // datareg
.int 0 // dataready
port1J:
.int 0x10800
// UART TX thread
TX:
ldap r11, port1J
ldw r0, r11[0] // get port 1J ID to r0
ldc r1, XS1_SETC_INUSE_ON
setc res[r0], r1 // turn the port on
ldc r1, 1
out res[r0], r1 // pin initial value = 1
ldc r2, 800 // with 800 run for 200,000 cycles; with 868 run for 30,000 cycles
TXloop:
setpt res[r0], r2 // set port time
ldc r1, 0
out res[r0], r1 // future pin value = 0
ldc r3, 4340
add r2, r2, r3
setpt res[r0], r2 // set port time
ldc r1, 1
out res[r0], r1 // future pin value = 1
ldc r3, 4340
add r2, r2, r3
bu TXloop
// unsigned main (void);
main:
// int UART (void);
// This non-returning function is called to initialize
// and run indefinitely the UART RX and a timer.
UART:
// initialize TX thread
getr r0, XS1_RES_TYPE_THREAD
ldap r11, TX
init t[r0]:pc, r11
start t[r0]
// initialize RXhandler
ldap r11, RXrecord
or r0, r11, r11 // r0 points to RXrecord
ldw r2, r0[1] // get portID to r2
ldc r3, XS1_SETC_INUSE_ON
setc res[r2], r3 // turn the port on
clrpt res[r2] // disable port timer
ldc r3, 1
setd res[r2], r3 // set comparison value
ldc r3, XS1_SETC_COND_EQ
setc res[r2], r3 // set port condition
or r11, r0, r0
setev res[r2], r11 // set environment vector = pointer to RXrecord
ldap r11, RXhandler
setv res[r2], r11 // set event vector
eeu res[r2] // enable events for this port
// initialize TIMERhandler
getr r0, XS1_RES_TYPE_TIMER
ldc r1, XS1_SETC_COND_NONE
setc res[r0], r1 // set timer condition to NONE
in r1, res[r0] // get current time
ldc r2, 434
add r1, r1, r2 // compute due time
setd res[r0], r1 // set due time
ldc r1, XS1_SETC_COND_AFTER
setc res[r0], r1 // set timer condition to AFTER
or r11, r0, r0
setev res[r0], r11 // set environment vector = timerID
ldap r11, TIMERhandler
setv res[r0], r11 // set event vector
eeu res[r0] // enable events for this timer
waiteu // wait for event
// "RXhandler" handles all the UART port events:
// * detecting the initial high level,
// * detecting the start bit,
// * sampling 8 data bits and the stop bit.
// See "RXstate encoding" at the beginning of the file.
// RXhandler runs perfectly if TIMER events are NOT enabled.
// It hangs on indefinitely if TIMER events ARE enabled,
// apparently because a port timer event was missed
// (and the subsequent one was NOT scheduled)
// when it occured in the same thread cycle as the TIMER event.
// This can be demonstrated by commenting in and out
// the timer "eeu" instruction above.
// The probability of a received character to block the RXhandler
// is apparently equal to 1 / (TIMER period in REF cycles), i.e.
// on average the RXhandler will run for "TIMER period" characters,
// before getting stuck.
// This suggests a possibility that a port timer event gets lost
// when it occurs in the same thread cycle as the TIMER event.
// RXhandler is usually stuck in the state "1", i.e. waiting
// for the port timer event in the middle of the first data bit.
// With decreasing probability, it was observed stuck in states "2" and "3",
// waiting for the middle of the second and third data bits.
// It was never observed stuck in states "0" or "10", i.e.
// waiting for a specific level on the input pin.
// Tested on XC1 board with a chip marked "XS1-G4A-FB512-C4 0835 ES N65285.00"
// I think this is the Rev. B of the architecture, and Rev. A of the silicon.
RXhandler:
get r11, ed // get environment vector = pointer to RXrecord
ldw r0, r11[1] // get portID
getts r1, res[r0] // get timestamp
in r2, res[r0] // get port data
ldw r3, r11[0] // get RXstate
bf r3, startbitfound
eq r4, r3, 9
bt r4, checkstopbit
eq r4, r3, 10
bt r4, waitstartbit // high level found
// RXstate in [1..8], sample a data bit
ldw r4, r11[5] // get shiftreg
shr r4, r4, 1
shl r2, r2, 7
or r4, r4, r2 // insert received bit
stw r4, r11[5] // save shiftreg
// now prepare to sample the next bit (data bit or stop bit)
add r3, r3, 1
stw r3, r11[0] // advance RXstate
ldw r1, r11[2] // get porttime
ldw r4, r11[3] // get 1.0 bits delay
add r1, r1, r4
stw r1, r11[2] // save porttime
setpt res[r0], r1 // set port time
waiteu
startbitfound:
add r3, r3, 1
stw r3, r11[0] // advance RXstate
ldc r3, 0
stw r3, r11[5] // clear shiftreg
ldc r4, XS1_SETC_COND_NONE
setc res[r0], r4 // set port condition
ldw r4, r11[4] // get 1.5 bits delay
add r1, r1, r4
stw r1, r11[2] // save porttime
setpt res[r0], r1 // set port time
waiteu
checkstopbit:
eq r4, r2, 1
bf r4, waithighlevel
ldw r4, r11[5] // get shiftreg
stw r4, r11[6] // save to datareg
ldc r4, 1
stw r4, r11[7] // set dataready
waitstartbit:
ldc r4, 0
stw r4, r11[0] // RXstate := wait for start bit
clrpt res[r0] // disable port timer
ldc r4, 0
setd res[r0], r4 // set comparison value
ldc r4, XS1_SETC_COND_EQ
setc res[r0], r4 // set port condition
waiteu
waithighlevel:
ldc r4, 10
stw r4, r11[0] // RXstate := waithighlevel
clrpt res[r0] // disable port timer
ldc r4, 1
setd res[r0], r4 // set comparison value
ldc r4, XS1_SETC_COND_EQ
setc res[r0], r4 // set port condition
waiteu
// "TIMERhandler" just reschedules the timer and waits
TIMERhandler:
get r11, ed // get environment vector = timerID
getd r9, res[r11] // load previous due time
ldc r10, 433 // TIMER period = 434 REF cycles
add r9, r9, r10
setd res[r11], r9 // set new due time
waiteu
You do not have the required permissions to view the files attached to this post.
-
- Member++
- Posts: 31
- Joined: Thu Dec 10, 2009 10:11 pm
Thank you for drawing attention to this and supplying such a clear description of the symptoms.
We have now been able to reproduce it on our simulators.
It appears to be a limitation of the port hardware. We will post some suggestions about how to avoid this problem
as soon as we have checked them.
We have checked that XC programs are not affected by this behavior - the instruction sequences compiled can not give rise to it.
Thank you for finding this issue and pointing it out to us. Can I offer you a reward - a free XC-1A or equivalent?
We have now been able to reproduce it on our simulators.
It appears to be a limitation of the port hardware. We will post some suggestions about how to avoid this problem
as soon as we have checked them.
We have checked that XC programs are not affected by this behavior - the instruction sequences compiled can not give rise to it.
Thank you for finding this issue and pointing it out to us. Can I offer you a reward - a free XC-1A or equivalent?
-
- Respected Member
- Posts: 318
- Joined: Tue Dec 15, 2009 12:46 am
As Dave says you have encountered a limitation of the port hardware. The issue concerns waiting for events on a unbuffered port configured to become ready at a port time with no condition. If the port becomes ready at the same time as another resource and the event for the other resource is taken then the port will not generate another event until its configuration is changed.
For now I wanted to get back to you with possible other approaches that would allow you to progress with your project.
One possibility is to instead configure the port as a buffered port. You can configure a port to be buffered using:
The effect of a timed input using a buffered port is slightly different to one using an unbuffered port. As with an unbuffered port, an unconditional timed input on a buffered port will become ready when the port time is met - at which point the the value on the pins is sampled. However, for a buffered port, at any subsequent tick of the port's clock new data will be sampled, overwriting the original value. Therefore if you set up an event for a buffered unconditional port but the thread is unable to take the event at the time it becomes ready (e.g. because it is busy handling other events) then the value read from the port after taking the event is the value input on the most recent clock tick and not the value when the time was first met.
For your application, it seems to me that this would work for the following reason. The maximum gap between the port time being met and the thread taking the event is bounded by the maximum time required to handle events on all the other resources in-between. The time required to service other events is likely to be small in comparison to one UART bit time as a UART is a relatively slow speed interface. Therefore the pin will be sampled very close to the middle of the each bit which should allow you to read the data correctly.
For now I wanted to get back to you with possible other approaches that would allow you to progress with your project.
One possibility is to instead configure the port as a buffered port. You can configure a port to be buffered using:
Code: Select all
setc res[r2], XS1_SETC_BUF_BUFFERS
For your application, it seems to me that this would work for the following reason. The maximum gap between the port time being met and the thread taking the event is bounded by the maximum time required to handle events on all the other resources in-between. The time required to service other events is likely to be small in comparison to one UART bit time as a UART is a relatively slow speed interface. Therefore the pin will be sampled very close to the middle of the each bit which should allow you to read the data correctly.
Last edited by richard on Sat Jul 24, 2010 12:40 am, edited 4 times in total.