Menu

UART Application Problem

Help
2010-04-21
2012-12-09
1 2 > >> (Page 1 of 2)
  • Dragan Grujičić

    Hello all,

    I must ask you again as last resort for some assistance because I hit the wall.
    After few weeks I return to UART app. Attached you will find it. Link to .zip project file is:
    https://docs.google.com/leaf?id=0B_OgQY_eYlI7N2Y5YTIzZjQtY2I3YS00MzZmLWEzZGUtYTVmYjcxNDg3ZTNk&hl=en

    It is based on HelloWorld example. It has two interrupts and two
    tasks. One task is led "Hello world" blink, other is UART loopback. I
    have one receive and one send interrupt.

    For testing I use Teraterm on USB/RS232 transceiver. I send FemtoOS
    Readme file over RS232 connection on different baudrares.

    UART is initialised correctly. If I use only receive  interrupt
    (modified of course) i can do 38.4k and it is max for 8000000 Hz
    crystal.
    If i use pooling ( void UART_loopback_pool(void) ) I can do 19.2.
    But I believe that using blocking on queue can do more. So begin problems:

    1. I can not use taskQueuReadRequestOnName(UARTRx,8) or any other
    number except 0. I get puntime error like this:
        Error 0x12: errSlotTypeMismatch     Slot used outside its definition.
        Calling API: 0x27
        Task: 1
    I can not find problem. Do not know what to do

    2. If i do not use:
       for (count=0; count<8; count++)
    and use
        taskQueuReadRequestOnName(UARTRx,0)
    inside void UART_loopback_sync(void) i can do only 9600 baudrate. It
    has something to do with 1ms tick. Please explain context switch
    timing.

    3. So I want to use burst data: I wait for 8 byte, obtain lock,
    disable context switch… But taskQueuReadRequestOnName(UARTRx,8) will
    not work? What am I doing wrong?

    4. Try to give Write task more time by raising priority on 3 (or
    higher) but then Display task will not run? Why?

    5. Also I can not compile for Compact only standard. Why?

    Any other opinion on sync, performance, code, anything… would be helpful.

    App is not even begin to be polished but works.

    Best regards

     
  • De Vlaam

    De Vlaam - 2010-04-23

    1. I can not use taskQueuReadRequestOnName(UARTRx,8) or …

    This is a bug, the checking mechanism thinks you made a
    mistake in using the call, but you did not. I have
    corrected (but not tested yet) it in the nightly build:
      http://www.femtoos.org/MainCode.zip
    Just take the femtoos_core.c file from the nightly and replace
    your version.

    Workaround in current version: set 'cfgCheckMethodUse' to 'cfgFalse'.
    Of course, then you loose other checking facilities as well.

    2. If i do not use …

    Full explanation of the context switch would take to much time,
    There is an article in Elektor, (but it is not free)
      http://www.elektor.com/magazines/2010/february/femto-os.1222123.lynkx?tab=3
    You can also have a look at (the larger) brother freeRTOS:
      http://www.freertos.org/implementation/a00002.html
    which explains the concept quite well.

    Short explanation: An OS switches tasks every 1ms (but you can
    change this). Anything you want to do that takes longer will
    be interrupted, for an other task. If you have two tasks,
    the communication task will be activated every other millisecond.
    This is devastating for time critical communication protocols.
    (See below for a solution)

    Please note the context switching in FemtoOS is more complex,
    since it allows for unequal time slices, but the basics are
    the same.

    3. So I want to use burst data …

    Try this with the correct version or with the work around.

    4. Try to give Write task more time …

    This is not the correct approach. If you give a task which
    has a 100% load the highest priority it will starve all
    other tasks with lower priorities. This is expected behavior.
    High priority tasks should delay often. But this is not what you
    want.

    So how do you approach this problem? There are several 'solutions'.
    (btw, this is a problem in every OS.)

    1) Make communication fully interrupt driven. This implies that
    every time a new byte must be written (standard avr has no dma)
    an interrupt occurs, and you must prepare a new byte. At 38.4 Kbaud,
    this is every 200us. A lot for a system running at 16MHz, and it
    will significantly increase the overhead, since each context switch
    costs a lot of instructions.

    2) Make a communication task at highest priority (as you did)
    so it has full control, but do not forget to stop it when
    communication is done. Disadvantage: all other tasks stop when
    the communication is running.

    3) Elongate the time slice to 10ms or so, and make the task
    quickly relinquish control when no communication is needed.
    In 10 ms you can transfer 48 bytes. If you can organize
    your communication in blocks of 48 bytes (or less), you'r fine.
    In FemtoOS it is possible to give one task a longer time slice
    than others, specially for this purpose:
      http://www.femtoos.org/code_config.html#1401
      http://www.femtoos.org/code_config.html#1804
      http://www.femtoos.org/code_config.html#1109

    Have a look at the following discussion too:

    https://sourceforge.net/projects/femtoos/forums/forum/789278/topic/3565410

    5. Also I can not compile for Compact only standard. Why?

    'Compact code' is for highly optimized code, forget about it until
    you have a good grasp of this OS. Then have a look at the demo's in
    detail. You will see that this kind of optimization requires detailed
    research about the registers used per task and stack depth analysis.

    regards
    Ruud

     
  • Dragan Grujičić

    First thing first:
    Last few days I have trouble connecting to your website. ?
    Now, when I am writing this there is no connection.

    Second:

    2) Make a communication task at highest priority (as you did)
    so it has full control, but do not forget to stop it when
    communication is done. Disadvantage: all other tasks stop when
    the communication is running.

    I thought I did so by using:

    void UART_loopback_sync(void)
        {
            Tchar RXdata = 0;
            Tuint08 count = 0;
            taskQueuReadRequestOnName(UARTRx,8);    //*1*
                    taskEnterSwitchCritical();                                        //*2*
                    // some code goes here
            taskExitSwitchCritical();                                          //*3*
            taskQueuReleaseOnName(UARTRx);               //*4*
        }
    

    At *1*: I ask for UARTRx queue: If there is 8 bytes i go further and with taskEnterSwitchCritical() I process all 8 byte without interruption and at *3* I let system work normal. If tick comes processing will be switched to other task on the same priority. I release queue and go for other 8 bytes. If I have continuous stream  of data I will be locked here. But If there is not 8 byte taskQueuReadRequestOnName(UARTRx,8) will block execution of current task and tell scheduler to suspend current task and let some other task do what it has to do. When 8byte are ready UART task will be ready and wait for next tick to start running. This should give some time for other task to do something (will they have enough time is another question). If UART is not active (no data flow) UART task will be blocked indefinitely and other tasks on other priorities will go on running with all the time in the world.

    So I ask if this is OK. Or I did not understand how queue synchronization is done?

    This is not what real communication will do. I will not have continuous stream of data that will block everything:

    Highest priority: control system that will keep real (mechanical, electrical..) world in stability and control. This would work in equidistant times (10 to 20 ms) and will be fairly quick.

    Lower priority: communication level with commands coming at random (sparse) times and data acquisition at equidistant times.

    Lowest: all other tasks

    So question is: Is taskQueuReadRequestOnName(UARTRx,dataLength) blocking task in the way that it will immediately release  processor and let other tasks run.

    As I can not download your code, could you email me femtoos_core.c. I will  try the workaround in the meanwhile.

     
  • Dragan Grujičić

    Tried workaround. Compiles and runs without error.
    But… If I use taskQueuReadRequestOnName(UARTRx,0) program runs and I get UART loop-back working correctly. At 19200 baudrate all characters loopback. At 38400 some characters are lost.

    But if I put taskQueuReadRequestOnName(UARTRx,8) or any other char count program get stacked at this place and nothing happens inside UART processing task. Second task runs as expected regardless of priority of the given tasks (no matter if UART task is higher priority).

     
  • De Vlaam

    De Vlaam - 2010-04-23

    Last few days I have trouble connecting to your website. ?

    Hmmm, i did not notice any downtime, and i call my server every
    five minutes. Could be the somewhere in the connection.
    I also saw some intensive attacks on my server, maybe
    that interfered with the normal httpd operations. Lets
    hope this problem disappears by itself. If it remains, (i.e.
    is still there in a couple of days) let me know, i will start
    complaining at the data center.

    Your code:

    This setup is ok. Indeed the taskQueuReadRequestOnName(UARTRx,8)
    should block until 8 bytes have arrived. If you put 0, the task
    would run at 100% load, so it starves other lower priority tasks.
    The disadvantage of putting 8 is of course that you can only send
    data in multiples of 8 bytes before processing begins. If you loose
    sync on the 8 byte boundary this may severely hamper the communication.
    Or you put in a 1, so it at least blocks until one character has
    arrived, but then the overhead per byte is still high, or you
    put in 8 or so with a 'timeout'. If you make sure you always pad
    your data with 8 bytes, you can throw away the last bytes, at a
    timeout.

    The fact that it does not work at all when you put in any other
    number than 0 i do not understand yet. You said that it blocks on
    the taskQueuReadRequestOnName(UARTRx,8) instruction itself. Have
    you verified that, in other words, you are sure it does not block in
    the part "// some code goes here" ?  This makes a difference when
    looking for the cause.

    You make use of taskEnterSwitchCritical() and states that it blocks
    interrupts, but this is not true. It prohibits task switches,
    but still allows for the tick interrupts to come, and thus for
    the tick counter to increase and the tick hooks to be punctual.
    This may be the reason for your loss of characters at the highest speed.
    You can also try taskEnterTickCritical(). This makes sure
    there are no tick interrupts any more, but still allows for
    other interrupts. Of course, time spend in between tick critical
    code must be minimal, and you should never block inside such
    a critical sections. If you do => system hangs.
    See
      http://www.femtoos.org/code_api.html#0416
      http://www.femtoos.org/code_api.html#0419

    OK i still do not understand why any other number than 8
    causes a permanent block. Can you post the code of the
    block "// some code goes here". [I have it in the zip, but
    do not know for sure if you did not modify it]. I have

    for (count=0; count<8; count++)
    {
      RXdata = genQueuReadOnName(UARTRx);

      if (RXdata)
      {
        //taskQueuWriteRequestOnName(UARTTx,8);
        genQueuWriteOnName(UARTTx,RXdata);
        UCSRB |= (1 << UDRIE);
        //taskQueuReleaseOnName(UARTTx);
      }
    }
    
     
  • Dragan Grujičić

    I will answer your last post in next y post but first this:

    1 Queue example from FemtoOS unchanged original state compiles and runs as described. I checked. It uses same queue functions as I do. So just put some char on queue and read it later. Only difference is that i use interrupts.

    2. Reading from UARTRx is blocking. Reading code I use now is:

    void UART_loopback_sync(void)
        {
            Tchar RXdata = 0;
            Tuint08 count = 0;
            //devLedPORT = ~0x0f;
            taskQueuReadRequestOnName(UARTRx,5);
            //devLedPORT = ~0xaa;
            //taskEnterSwitchCritical();
            for (count=0; count<8; count++)
            {
                RXdata = genQueuReadOnName(UARTRx);
                //devLedPORT = ~RXdata;
                if (RXdata)
                {
                //taskQueuWriteRequestOnName(UARTTx,8);
                genQueuWriteOnName(UARTTx,RXdata);
                UCSRB |= (1 << UDRIE);
                //taskQueuReleaseOnName(UARTTx);
                }
            }
            //taskExitSwitchCritical();
            taskQueuReleaseOnName(UARTRx);
        }
    

    I can use any number of characters for blocking and the result is the same. You can see I commented out some code just to be sure.

    3. For writing I use modified ISR:

    void USART_RXC_vect(void) __attribute__ ( ( signal, naked, used, externally_visible ) );
        void USART_RXC_vect(void){
            isrEnter();
            genQueuWriteOnName(UARTRx,UDR);
            devLedPORT = ~genQueuReadableOnName(UARTRx);
            isrExit();
            }
    

    As you can see ISR is displaying number of characters ready to be read from queue.

    4. Results are as follows:

    - if I use taskQueuReadRequestOnName(UARTRx,0) at 19200 baudrate no more then 3 characters are in queue at anytime and all characters are looped back. No characters are lost. At 38400 queue gets filled to max of 30 chars (size of queue) and some characters are lost (approximately every other) but UART loopback is working.

    -if I use taskQueuReadRequestOnName(UARTRx,5) queue gets filled to maximum and no characters are looped back. I tried keyboard input of characters and all is the same, no characters are looped back. All characters are received and put to queue but never read from it? I also tried peeking into queue and reading from queue inside ISR and putting chars on ledPort and all is OK.  Queue is filling.

    5. Please consider that I might be doing something stupid in coding or configuration.

     
  • Dragan Grujičić

    In my previous post you can notice that I am not using critical section protection, just to be sure also  you can notice this arangement:

    devLedPORT = ~0x0f;
            taskQueuReadRequestOnName(UARTRx,5);
            devLedPORT = ~0xaa;
    

    Also all other writing to devLedPORT is disabled (except these two) and program never get to devLedPORT = ~0xaa when blocking count is more then 0. also when sending stream of data I see these two values together on leds, as change is too fast for leds to switch off. And again data flows.

    This is now no problem of performance. The problem is that I can not block on queue, or to be correct task blocks indefinitely.

    I could use event in ISR and dedicated task in high priority but it does not solve the problem. May me the queue synchronization would work when only queues are involved in filling/reading queue. May be using ISR is problem.

    Or again I am doing something stupid. Would not be the first time :-))

     
  • Dragan Grujičić

    devlaam wrote:

    OK i still do not understand why any other number than 8
    causes a permanent block.

    Sorry for misunderstanding: any other number than 0 causes permanent block. It has nothing to do with number 8. You can pick any number you like. I tried.

     
  • De Vlaam

    De Vlaam - 2010-04-23

    I understood your points in your last two post fully. I think there is a "flaw" in my design. You said "Only difference is that i use interrupts". This triggered my suspicion. It looks like the block is erroneously not released when the characters are added in a ISR. But this is not the case. The problem is, that in my design, taskQueuReadRequest / taskQueuRelease form a pair. So, only after a formal release other requests are reexamined. There where reasons for that, which i shall not discuss now (**). But in an ISR you cannot use those calls, so, although you can read/write a queue, you cannot use it to deblock any blocking calls right now. Your design was so natural i forgot all about this limitation. My apologies.

    The question is, how to repair this? It seems logical to add deblocking code to genQueuWrite, but it is not the correct solution. I could add a new call specially for inside an ISR, that you may call to force such a check. But this would still require you to call it after the addition of every byte, which really adds much more overhead at the point it hinders you most. It would certainly slow down communication. So I have to think about it.

    For you, the best way would be to simply add a time out, with a wait time low enough prohibiting the queue from overflowing.
    Thus, if your queue is 30 bytes, keep some margin, and set the limit to 24 bytes. To fill these at max speed you need 8x24/38400 = 0.005, so 5 ms. (you can even make this dynamic, dependant on your communication speed) In fact, you are using a spinlock. Now you get something like (untested)

    void UART_loopback_sync(void)
    { Tchar RXdata = 0;
      Tuint08 count = 0;
      /* wait until at least 8 characters have arrived, make sure that
       * you do not wait more than 5ms, so that there never more than
       * 24 bytes in the queue. Note that this loop is relatively fast,
       * this task will not produce much overhead, when no characters are
       * arriving. */
      while (!taskQueuReadRequestOnName(UARTRx,8,5));
      /* now read 8 characters */
      for (count=0; count<8; count++)
      { RXdata = genQueuReadOnName(UARTRx);
        /* actually, this if is not needed, you know that there must be a valid character. */
        if (RXdata)  
        { genQueuWriteOnName(UARTTx,RXdata);
          UCSRB |= (1 << UDRIE);  } }
      taskQueuReleaseOnName(UARTRx); }
    

    Please note that in between a taskQueuReadRequest / taskQueuRelease pair characters may still arrive and are added to the read queue. This is perfectly ok.

    I am curious if this works.

    Ruud.

    (**) One of them is that adding that to the genQueuWrite/genQueuRead routines would not keep them short,as required in ISR environment. Others have to do with the internal design. Allowing it would require extra checks and protection routines and thus further bloating the OS.

     
  • De Vlaam

    De Vlaam - 2010-04-23

    This forum sucks. I tried three times to codify the code, but the forum engine simply deletes the first 'code' statement.

     
  • Dragan Grujičić

    First things first:

    Added: while (!taskQueuReadRequestOnName(UARTRx,8,5));

    and get compile error:

    ../src/FOS_driver_UART.c:79:47: error: macro "taskQueuReadRequestOnName" passed 3 arguments, but takes just 2

    API claims that there is call to taskQueuReadRequestOnName with 3 arguments. Queue example project from OS uses macro with 3 arguments and compiles with no problem.

    Or again I am doing something stupid. Would not be the first time :-))

    I checked OS files in both src dirs and they are identical. Only thing that is different are config files. and of course project files.

    Again it must be me. Is there a config situation to include only macro with 2 and not 3 arguments.

    It must be me doing crazy things.

     
  • De Vlaam

    De Vlaam - 2010-04-24

    Or again I am doing something stupid. Would not be the first time :-))

    This time, i must admit it ;-)

    Any (well most) functionality you want to use you must activate in the configuration file. Of course, i could have added all functionality in the kernel by default, but that would bloat the OS with stuff you may never need. I agree, that Femto OS is a little rough in this aspect., thats the price to be paid for very small systems. Thus in any case, you have to activate:

     #define  cfgUseTimeout  cfgTrue
    

    And the task must have delay capabilities, but i think you have already set capabilities to all (cfgCapAll)
      http://www.femtoos.org/code_config.html#1830
    If you get an compiler error, have a look at the warnings too. Often, my checking system reports misuse and inconsistent use of configuration settings. Never ignore warnings! In my opinion, a program should compile without warnings.

    One other remark.

    I saw you configured

    #define  cfgUseSynchronization  cfgSyncSingleSlot
    

    This is fine as long as you are not occupy more than one slot per task at the same time. In the code however i saw that you use two when requesting the write and read queue. (Writing to the queue does not require a slot, but reserving it for yourself does)

    // requesting the first slot    
    taskQueuReadRequestOnName(UARTRx,8);
    taskEnterSwitchCritical();
    for (count=0; count<8; count++)
    {
      RXdata = genQueuReadOnName(UARTRx);
      if (RXdata)
      {
      // requesting the second slot, if you include the statement below
      taskQueuWriteRequestOnName(UARTTx,8);
      genQueuWriteOnName(UARTTx,RXdata);
      UCSRB |= (1 << UDRIE);
      taskQueuReleaseOnName(UARTTx);
      }
    }
    taskExitSwitchCritical();
    taskQueuReleaseOnName(UARTRx);
    

    please see the discussion on
      http://www.femtoos.org/code_config.html#1404
    Then you need

    #define  cfgUseSynchronization  cfgSyncSingleBlock
    ...
    #define  SlotSize_Write                      2
    #define  SlotSize_Display                  0
    // i saw that the display task does not use locking at all
    
     
  • Dragan Grujičić

    At this point I must ask for a help/opinion:

    Lets put beginning and end together:

    I started UART driver in order to have some feedback and insight what is going on inside MCU during execution of OS and to use functions inside Shell application to check for performance. Also I need it do do some data collection for further PC processing.

    To start most natural thing was to make "digital parrot" that will repeat all i send to it. When I got loopback I wanted to see how fast can communication be in order to use most efficient way. It is not my intension to have continuous stream of data flowing in and out at all times. For now it is only convenient way to test the overall setup. Ultimately I hope to have kind of putchar/getchar, puts/gets paits and pipe functionality (as in shell example and everywhere I look in other applications).

    So the idea is following: I use queues as data buffers and synchronization mechanism to achieve asynchronous data flow in/out. Data processing task is inactive until there is enough data communication. Only at this point task is activated and data is processed. When all available data is processed task is suspended again.

    In order to have this work "naturally" writing and reading queue must block.

    Reading and writing communication hardware can be done in 2 way: in one way ISR will read and write to queue, in other ISR will will fire an event what will wake task to do actual read/write.

    But now I see problem: if ISR is used we have problems described before. If event and task is used I see similar problem:

    Proposed solution with  while (!taskQueuReadRequestOnName(UARTRx,8,5)); is, in my opinion,  just a better pooling: instead of pooling all the time, queue is pooled (effectively) every 5ms ant this is not "wait for enough data and only then begin processing" strategy. Timeout here is used, in my opinion, to have time critical notification in case of communication troubles.

    The way I see things solution is:

    taskQueuReadRequestOnName(UARTRx,8);
    while (allDataIsProcessed)
    {
        RXdata = genQueuReadOnName(UARTRx); 
        processData(RXdata);
    }
    taskQueuReleaseOnName(UARTRx);
    

    This is not working for me when writing to queue inside ISR, for reasons described before.

    How will this work in case of event and task writing to queue: ISR fires an event that will wake a high priority task to write queue using genQueuWriteOnName(UARTRx,UDR);. Question is: if this function is used inside task does it have to be inside
    taskQueuWriteRequest / taskQueuRelease to have correct reading synchronization? If this is a case then there could be problem if queue if full. Then no data would be read from UDR until there is empty place inside queue. This, on the other hand, could be solved by requesting 0 byte for writing inside  taskQueuWriteRequest.

    But there is even bigger problem:
    Page 152 of Atmega16 manual:

    When interrupt-driven data
    transmission is used, the Data Register Empty Interrupt routine must either write new data to
    UDR in order to clear UDRE or disable the Data Register empty Interrupt, otherwise a new interrupt
    will occur once the interrupt routine terminates.

    Page 156 of Atmega manual:

    When interrupt-driven data reception is used, the receive complete routine
    must read the received data from UDR in order to clear the RXC Flag, otherwise a new interrupt
    will occur once the interrupt routine terminates.

    So using ISR to fire event also requires reading UDR in order to stop repeating interrupts , having global variable to store data.
    Than this global variable is to be stored in queue inside high priority task.

    So, any solution I see is not optimal in any way.
    I do not know what to do!

    Help!?

     
  • Dragan Grujičić

    Crazy:
    femtoos_ATMega32A.asm:

    #define devAuxEventReg    UBRRL

    And I need this for events and UART too.

     
  • De Vlaam

    De Vlaam - 2010-04-24

    We discussed this before. There is no GPIO on this device. The device architecture is ancient. Choose an other device, or choose a register you do not need. It must be in the lower IO (<0x20) region.

    I will react to your other points later on, but i believe the event system is just the solution to your problems. Untested:

    void USART_RXC_vect(void)
    { isrEnter();
      genQueuWriteOnName(UARTRx,UDR);
      IsrFireEventOnName(IncomingByte);
      isrExit(); }
    void UART_loopback_sync(void)
    { Tuint08 count;
      taskWaitForEventOnName(IncomingByte);
      Tuint08 size = genQueuReadableOnName(UARTRx);
      for (count=0; count<size; count++)
      { Tchar RXdata = genQueuReadOnName(UARTRx);
        genQueuWriteOnName(UARTTx,RXdata);
        UCSRB |= (1 << UDRIE); } }
    

    And in the configfile on the appropiate places:

    #define  cfgUseEvents                            cfgTrue
    /* Event functions --------------------------------------------------------- */
    #define  includeTaskWaitForEvents                cfgTrue
    #define  includeIsrFireEvent                     cfgTrue
    #define  includeGenFireEvent                     cfgFalse
    #define  includeGenFireEventSet                  cfgFalse
    #define  includeGenCountEventBlocks              cfgFalse
    /* EVENT NAMES */
    #define  EN_00                                   IncomingByte
    

    Of course, it also possible to use the interrupt (with isr) solely to wake a high priority task, which fully handles the incoming bytes. This is polling, but guarantees maximum throughput. In that case, the ISR looks (note the absent isrEnter/isrExit!)

    void USART_RXC_vect(void)
    { IsrFireEventOnName(IncomingByte); }
    

    And handle everything else in the task. Now rereading your post, i see you must disable the interrupts manually also. Please add this in the ISR, and enable them again in the high priority task once communication is over. I do not have the time right now to come with some working code examples, but i don't think its to difficult.

    Question is: if this function is used inside task does it have to be inside
    taskQueuWriteRequest / taskQueuRelease to have correct reading synchronization?

    No, as i explained earlier, this calls are only to needed if you want exclusive access to your queue. This is not needed if you have only one task reading and one task writing. (If you have more tasks writing for example, you need this to make sure the messages are not mixed). With genQueuReadableOnName(UARTRx) you can test if there are bytes ready to be processed.

     
  • Dragan Grujičić

    Again; I have been busy and worked some code my self like this:

    volatile Tuint08 count1 = 0;
    void USART_RXC_vect(void) __attribute__ ( ( signal, naked, used, externally_visible ) );
        void USART_RXC_vect(void){
            isrEnter();
            //devLedPORT = ~count++;//~genCountEventBlocksOnAll();
            genQueuWriteOnName(UARTRx,UDR);
            isrFireEventOnName(UARTRx_EV);
            isrExit();
            }
    void UART_loopback_sync(void)
        {
            Tchar RXdata = 0;
    
            taskWaitForEventOnName(UARTRx_EV);
            devLedPORT = ~count1++;
            RXdata = genQueuReadOnName(UARTRx);
            genQueuWriteOnName(UARTTx,count1);
            UCSRB |= (1 << UDRIE);
        }
    

    Note count1 in genQueuWriteOnName.

    Also:

    femtoos_ATMega32A.asm:
    #define devAuxEventReg TWDR
    

    In config_application.h:

    /* ========================================================================= */
    /* EVENT NAMES ============================================================= */
    /* ========================================================================= */
    #define EN_00                                   UARTRx_EV
    #define EN_01                                   UARTTx_EV
    /* Event functions --------------------------------------------------------- */
    #define  includeTaskWaitForEvents                cfgTrue
    #define  includeIsrFireEvent                     cfgTrue
    #define  includeGenFireEvent                     cfgTrue
    #define  includeGenFireEventSet                  cfgTrue
    #define  includeGenCountEventBlocks              cfgTrue
    #define  cfgUseEvents                            cfgTrue
    

    This should work like this: ISR reads character, writes queue and fires event. Task blocks on event and waits for first char to arrive.

    But…

    If I uncomment in ISR

    //devLedPORT = ~count++
    

    and comment corresponding instruction in UART_loopback_sync I can see on led port count incrementing on every new character. And this is correct. So event is fired only when new character arrives. At least this is what I think.

    But if I run this code as shown above, as soon as program is loaded strange things begin: leds on devLedPORT flash like crazy and in PC terminal application I get tons of garbage.

    To me this is indication that task is not blocking on event for some reason and just loops and loops on indefinitely.

    Help!?

     
  • Dragan Grujičić

    If I use your code with addition of counter inside task same thing happens. Leds flash like crazy just after I download hex without any UART communication started. If characters are send to MCU they are looped back.

    May be the problem with TWDR register I used? Will check.

    No. If I use SPDR the same thing happens.

     
  • De Vlaam

    De Vlaam - 2010-04-24

    To me this is indication that task is not blocking on event for some reason and just loops and loops on indefinitely.

    This conclusion seems valid

    May be the problem with TWDR register I used? Will check.
    No. If I use SPDR the same thing happens.

    I am not sure this is conclusive. Reading or writing those registers activates further events in the mcu. I would take a free port (just for the moment). If you define them as output, you can even see what is happening on the outside. If this helps, we need to find an other register that is free. Let me know.

     
  • Dragan Grujičić

    Tested:

    void appBoot(void)
    {
      devLedDRR    = 0xFF;
      devLedPORT   = 0xFF;
      DDRC    = 0xFF;
      PORTC   = 0xFF;
      devSwitchDRR = 0x00;
      taskDisableGlobalInterrupts();
      uart_init();
      taskEnableGlobalInterrupts();
    }
    
    #define devAuxEventReg    PORTC
    

    The same situation:

    On devLedPORT leds are flashing. On PORTC no leds are on.

    When stream data is sent over UART at 19200  baud no led again is set. I would expect that at least one should change state when event is fired.

     
  • De Vlaam

    De Vlaam - 2010-04-24

    Have you set cfgUseEvents to cfgTrue (in configfile)? 

     
  • De Vlaam

    De Vlaam - 2010-04-24

    Never mind, you stated you did.

     
  • Dragan Grujičić

    Please always have in mind that it might be me doing something stupid. I do not have too mush coding experience.

     
  • Dragan Grujičić

    Solved problem with events and ISR.

    It pays to "Clean project" command from time to time.

    System works as intended. Cad do 19200 baud continuous stream data and 38400 baud keyboard data.

    Will have some finished code soon.

    Best regards.

     
  • De Vlaam

    De Vlaam - 2010-04-26

    It pays to "Clean project" command from time to time.

    Indeed, you learned it the hard way :-(. Anyway, nice you tackled the problem! BTW, i always clean before compile, and this is my practice for so long now, that i had forgotten about the effects it may give when you don't. Programs are so small that the extra compile time does not outweighs the time spend searching for strange bugs!

    Can do 19200 baud continuous stream data and 38400 baud keyboard data.

    So it seems that 38400Kbd, which requires a guaranteed response time of 200us/char is just too much. I am a little surprised, but maybe you can get some extra speed if you deactivate all QA check functions. Thus, set all cgfCheck…. definitions to cfgFalse. The other thing you can do is to use the register compression facility. But be prepared to suffer, since this is the last optimization step to be taken, and may quickly result in the program going haywire. So this is only the last resort.

     
1 2 > >> (Page 1 of 2)

Log in to post a comment.