Is the timing of "millis();" somehow in anyway tied to Serial comport #2 via
interrupts or timers or DMA?
I am hammering both comports #1 & #2, and millis seems to reset on comport #2 activity.
Is the timing of "millis();" somehow in anyway tied to Serial comport #2 via
interrupts or timers or DMA?
I am hammering both comports #1 & #2, and millis seems to reset on comport #2 activity.
When you write that "millis() seems to reset", do you mean becomes zero (or very close), or jumps about?
The underlying value used by millis(), called systick_timer_millis, is updated by the interrupt service routine of a special purpose timer called SysTick timer.
The SysTick timer is an independent interrupt, unrelated to, e.g. the USARTs (RM0008 Reference Manual, document 13902.pdf from st.com).
I had a look at the millis() maplelib source, and the underlying SysTick timer source. After digging through the RM0008 processor manual, and "STM32F10xxx Cortex™-M3 programming manual (PM0056)", I can honestly say, I don't know what might be causing that.
The processor shouldn't lose any interrupts as long as their is enough time to process them all.
I failed to figure out which has a higher interrupt priority between the USARTs and SysTick, so I can't tell if it is possible for a USART to starve the SysTick interrupt handler, but I can't think how that might be possible.
Edit: { I didn't find where the interrupt handlers are attached to the interrupts, but I can't see that the code might be called sometimes and not others, unless there is a significant bug. I can't see how USART2 might cause this.
Also, the systick_timer_millis is a 32bit value, so even if, somehow, two pieces of code tried to update it, updates might be lost, causing it to increase less often than it should, but I don't understand how it might get reset or jump around.
}
Is it possible that a buffer is overrunning, and writing on millis() underlying systick_timer_millis SysTick timer value?
My Quote: "I am hammering both comports #1 & #2, and millis seems to reset on comport #2 activity."
Change "seems" to "is" ... millis is reseting to zero then restarting on comport #2 activity.
Quote: "do you mean becomes zero (or very close), or jumps about?"
Reply: reset to zero and starts counting again. (no jumping about)
Quote: "Is it possible that a buffer is overrunning"
Reply: No, I am using serial2.flush to prevent this from happening.
I found out by overrunning a receiver buffer will bring about
"The Blue Status LED Throbbing" which halts the ARM in an infinite loop.
That does sound like a buffer or array overrun/underrun, or a deep bug.
Have you some other arrays?
Can you over-allocate arrays to see if the problem changes?
Is there a practical way to check for overrun/underrun? E.g. would the code support putting 'padding' (extra space) around the arrays, and fill the 'padding' with a distinct non-zero 'sentinel' value, then check the padding sentinel values are unchanged?
Maybe if you want to publish code, someone might see something?
Sorry I can't be more helpful.
(BTW - May I ask, what time zone are you in? I read your post a couple of hours ago (then 5 hours old), did some digging, wrote a reply, and you're back within the hour - I'm impressed:-)
While digging, I noticed a tiny, but annoying detail, which should make no difference to the bug, but thwarted my grep.
class HarwareSerial is declared as
class HardwareSerial : public Print {
...
virtual void write(unsigned char);
...
};
the Print class hasn't got the corresponding textual form:
class Print
{
...
public:
virtual void write(uint8) = 0;
...
};
So I was grep'ing for 'write(unsigned char' and couldn't find it! So I went and looked at every 'write'.
I accept this is a miniscule detail, but it would have saved a little bit of time. So LeafLabs, would you add fixing that as a low priority (as if such low priorities ever work their way to the front of the queue :-)
Quote: "That does sound like a buffer or array overrun/underrun, or a deep bug."
Reply: No, I use the serial flush command this prevents the "Blue Status LED Throbbing"
Quote: "Have you some other arrays?
Can you over-allocate arrays to see if the problem changes?
Is there a practical way to check for overrun/underrun? E.g. would the code support putting 'padding' (extra space) around the arrays, and fill the 'padding' with a distinct non-zero 'sentinel' value, then check the padding sentinel values are unchanged?
Reply: No arrays are used.
TZ = EST
Here goes ...
-------------------------------------------------------------------------------------
Platform: Windows XP SP3
Device: Maple (red) rev 3
IDE: 0.0.6
External Hardware: 4D Systems "down under" uLCD-32PT(SGC) Serial QVGA LCD Touch Screen with SD.
Comports used: Serial1: For diagnostics from QVGA touch screen
Serial2: Serial TTL connection to uLCD-32PT LCD Touch QVGA
--------------------------------------------------------------------------------------
Code description/operation:
In the main loop I have a Millis 5 min. LCD screen saver to prevent "burn out".
I also have a 1 sec millis(); to poll the touch screen. The function
"ouled.get_Touch_Coord(0x00); will send back to comport Serial1 the coordinates of the touch.
The touch coordinates (4 bytes) then gets printed to Serial2 for diagnostics. The moment,
I press the touch screen, with a non zero coordinates, the serial transmission begins which
resets the "screen saver millis" to zero for no reason. Without any comm activity on Serial2
from the touch screen, the "screen saver millis" works fine.
The general operation is this. I am sending a setup command serially to comport #1 to the
touch screen. The touch responds with a 4 byte touch coordinate and transmits back
on comport #1. The Maple redirects the touch coordinates to diagnostic comport #2.
The serial flow activity from comport #2 resets the millis timer to zero and restarts.
The millis timer should never reset except for once every 67 days?
--------------------------------------------------------------------------------------
----------
Beta Code:
----------
/*
Description: uLCD-32PT QVGA Touch Test Code
Author: Hacker
Date: 9/3/10
Time: xxxx
Platform: Win XP SP3
Device: Maple red rev. 3
IDE: 0.0.6
*/
/* color is a 16 bit value.
binary representation 1111111111111111 (this will give white) same as 0xffff in hexadecimal or 65535 decimal
// |||||-> value for blue
// ||||||-> value for green
// |||||-> value for red
*/
//------------------------------------------------------------------------------------------------------------
#include <uOLED.h>
#include <colors.h>
#define COMM Serial2
#define DIAG Serial1
#define BLUE_LED_PIN 13
uOLED uoled; // <------<<<<<<<< Create an instance of the uOLED class
byte i,j; // some variables for looping
int color=0; // a variable named color with an initial value of 0 (black)
char result = 0;
int toggle = 0;
int interval_T_Scan = 1000; //touch scan processing time
unsigned long startTime_T_Scan;
long interval_Screen_Saver = 300000; // 300 secs screen save - shut display down / off
unsigned long startTime_Screen_Saver;
void check_Res(void){
result = uoled.res;
if (result == 0x06){
DIAG.println("ACK - Good");
}
if (result == 0x30){
DIAG.println("NAK - Bad!");
} // zero '0' is used for NAK
}
void draw_uLCD_Display(void)
{
// draw display screen
uoled.Rectangle(0,0,239,319,WHITE,FULL); // draw a rectangle with color white
uoled.Line (1, 40, 239, 40, WHITE); // draw a line with color white
uoled.Line (1, 233, 239, 233, WHITE); // draw a line with color white
uoled.TextButton(1,25,50,BLUE,SMALL_FONT,WHITE,1,2,"Option 1");
uoled.TextButton(1,25,80,BLUE,SMALL_FONT,WHITE,1,2,"Option 2");
uoled.TextButton(1,25,110,BLUE,SMALL_FONT,WHITE,1,2,"Option 3");
uoled.TextButton(1,25,140,BLUE,SMALL_FONT,WHITE,1,2,"Option 4");
uoled.TextButton(1,25,170,BLUE,SMALL_FONT,WHITE,1,2,"Option 5");
uoled.TextButton(1,25,200,BLUE,SMALL_FONT,WHITE,1,2,"Option 6");
uoled.TextButton(1,150,50,BLUE,SMALL_FONT,WHITE,1,2,"Option 7");
uoled.TextButton(1,150,80,BLUE,SMALL_FONT,WHITE,1,2,"Option 8");
uoled.TextButton(1,150,110,BLUE,SMALL_FONT,WHITE,1,2,"Option 9");
uoled.TextButton(1,150,140,BLUE,SMALL_FONT,WHITE,1,2,"Option 10");
uoled.TextButton(1,150,170,BLUE,SMALL_FONT,WHITE,1,2,"Option 11");
uoled.TextButton(1,150,200,BLUE,SMALL_FONT,WHITE,1,2,"Option 12");
}
void turn_Display_On(void){
uoled.SetPowerState(1); // display powerup
uoled.SetContrast(5); // set the contrast of the display to 5 (0 to 15 default (not always) is 8)
draw_uLCD_Display(); // redraw screen
}
void setup()
{
COMM.begin(9600); // Default comport for uLCD display @ 9600
DIAG.begin(9600); // Diag comport - for program ack/nak/info
delay(10000); // wait 10 seconds for POR for display and memory card init. Will show splash screen
// move to 3 seconds to skip splash screen
DIAG.println("Check Comm. to 4D Labs Display"); //
uoled.begin(9600, &COMM); // serial speed 9600
// reset and initialize the display
check_Res(); // check response and print to Diag port
COMM.flush(); // clear serial buffer
delay(1000);
DIAG.println("Change or step baud rate up to 128,000 max. baud"); // uLCD does not have autobaud!
uoled.step_baud_up(); // new baud rate in uLED.cpp (adjustable)
check_Res(); // check response
COMM.end(); // end "old" serial comm and restart at the new higher baudrate
COMM.begin(128000); // this value should match the same in uLED.cpp (adjustable)
COMM.flush(); // clear serial buffer
DIAG.println("Set Contrast to 5");
uoled.SetContrast(5); // set the contrast of the display to 5 (0 to 15 default (not always) is 8)
check_Res(); // check response
delay(500);
DIAG.println("Show Device Display Info");
uoled.DeviceInfo(); // display some hardware/software info of the screen
COMM.flush(); // clear serial buffer - info also when to the serial port! flush it.
delay(3000); // info will be on screen for 3 seconds
DIAG.println("Clear screen");
uoled.Cls(); // clears the screen of everything on it. It uses the background color (at this moment it's at default black)
uoled.Cls(); // keep <---- bug fix - no res without it - needs 2 of them?
check_Res(); // check response
DIAG.println("Turn Touch On");
uoled.DisplayControl(0x05,0x00); // turn touch on
check_Res(); // check response
/* Set up the LED to blink */
pinMode(BLUE_LED_PIN, OUTPUT);
DIAG.println("redraw display");
draw_uLCD_Display();
delay(10000);
//DIAG.println("Turn display off");
//uoled.SetDisplayState (0x00); // display off -
//delay(3000);
//DIAG.println("Turn display on");
//uoled.SetDisplayState (0x01); // display on - no redraw necessary
//delay(5000);
//DIAG.println("display powerdown - low power mode");
//uoled.SetPowerState(0); // display powerdown (low power mode) 0.080 ma.
//delay(5000);
//DIAG.println("display powerup");
//uoled.SetPowerState(1); // display powerup - redraw is necessary!
//DIAG.println("set contrast");
//uoled.SetContrast(5); // set the contrast of the display to 5 (0 to 15 default (not always) is 8)
//DIAG.println("redraw display");
//draw_uLCD_Display();
startTime_T_Scan = millis();
startTime_Screen_Saver = millis();
DIAG.println("Turn Touch On");
uoled.DisplayControl(0x05,0x00); // turn touch on
check_Res(); // check response
DIAG.println("Detect Touch Region");
//void detect_Touch_Region(unsigned int x1,unsigned int y1,unsigned int x2,unsigned int y2);
uoled.detect_Touch_Region(0,0,239,319); // whole region <------ modify per application
check_Res(); // check response
} // end of setup
void loop()
{
// uoled.x_res is the horizontal resolution of the display u are using.
// uoled.y_res is the vertical resolution of the display u are using.
// portait uLCD-32PT(SGC)
uoled.x_res = 240;
uoled.y_res = 340;
//-------------------------------------------------------------------------
// do this when not doing touch scan - below
//-------------------------------------------------------------------------
toggle ^= 1;
digitalWrite(BLUE_LED_PIN, toggle);
//delay(50);
// blank screen after 5 minutes
if ((millis() - startTime_Screen_Saver) > interval_Screen_Saver)
{
uoled.SetDisplayState (0x00); // display off
uoled.DisplayControl(0x00, 0x00); // backlight off
//startTime_Screen_Saver = millis();
}
//<------------------------------------------------------------------------|||
// do Touch Scan every second
if ((millis() - startTime_T_Scan) > interval_T_Scan){
uoled.get_Touch_Coord(0x00); // wait for touch activity
// response will be 4 bytes or nothing ... the screen has to be pressed before calling this function for a vaid response.
DIAG.println((millis() - startTime_Screen_Saver),DEC); // print millis for screen saver
if ((uoled.coor_x == 0) || (uoled.coor_y == 0))
{
}
else
{
// for test only
//DIAG.println(uoled.byte1,DEC);
//DIAG.println(uoled.byte2,DEC);
//DIAG.println(uoled.byte3,DEC);
//DIAG.println(uoled.byte4,DEC);
DIAG.print("Touch Response COOR. x=");
DIAG.print(uoled.coor_x,DEC);
DIAG.print(" y=");
DIAG.println(uoled.coor_y,DEC);
// for screen saver
uoled.SetDisplayState (0x01); // display on - no redraw necessary
uoled.DisplayControl(0x00, 0x01); // backlight on
//startTime_Screen_Saver = millis(); // restart screen saver timer <-- for
troubleshooting
}
COMM.flush(); // flush the trash after every touch scan <--------------------<<<<<<<<<<<<<<<
startTime_T_Scan = millis(); // restart millis timer
} // end of millis "if"
} // end of main loop
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
Hmmm, interesting bug, ... good luck :-)
Is it provoked by using *only* comport 2, or does it need some activity on comport 1 while comport 2 is active?
(I was EST, in MA, but now back to BST, and this month Zulu, my favourite !-)
It seems when I shutdown serial2 millis seems to work.
Interrupts or something is blocking millis when using serial port #2.
Maybe the serial ports have a higher priority than the systic?
Further testing on going ...
Andy, I really have no idea what is causing that behaviour.
As far as I can see there are only two lines of code in the whole library which change the underlying millis() variable, systick_timer_millis. It is changed in systick.c.
One is systick_timer_millis = 0;
the other is systick_timer_millis++;
The only way that I can see to get the systick_timer_millis = 0;
is to start the program from scratch because the variable is initialised to 0, and not assigned 0 in any ordinary function.
Otherwise, it seems likely that something might be scribbling into systick_timer_millis.
Can you copy systick.c, and compile it as part of your sketch. This might move systick_timer_millis in memory, so that the bug moves (might not of course).
You could also modify a copy, and put some padding around systick_timer_millis to see if things change.
That's my best idea.
Strange indeed!
gbulmer, if you're looking at the 'master' branch of libmaple, the SysTick system has been improved and rewritten, so this may be a problem specific to the v0.0.6 release. To paraphrase the commit log: "Fixed millis(), it was just wrong, before."
andy, hopefully your problem will be gone in the 0.0.7 release.
You must log in to post.