Show Posts

This section allows you to view all posts made by this member. Note that you can only see posts made in areas you currently have access to.


Messages - tdrobnak

Pages: [1] 2
1
Thank you, Mark for the explanation and offer to add emulation support for EEPROM emulation of FlexNVM.  When I get to a stopping point on my present task with this application, I will send you a file that provides FlexNVM EEPROM emulation support to uTasker in the hardware.

Tom

2
NXPTM M522XX, KINETIS and i.MX RT / uTasker FlexNVM Simulator support
« on: March 03, 2020, 02:54:19 PM »
Does anyone know if uTasker supports FlexNVM for EEPROM emulation?  NXP has two application notes on the subject:
  • AN4282 - Using Kinetis Family Enhanced EEPROM Functionality
  • AN5338 - How to use FlexMemory as D-Flash and EEPROM in KE1xF

I have looked through uTasker 1.4.12 and found no driver for FlexNVM so I added the necessary driver code from the NXP SDK 2.7.0 flexnvm_eeprom.c example.  I now have access to EEPROM emulation using FlexNVM when run on the hardware.  When I run on the uTasker simulator, I receive exceptions on access to the registers that control FlexNVM partitioning and status.  Has anyone else run into this situation?  Is there a way to work around it?

Thank you.

3
Has anyone tried using two I2C channels on one microcontroller devices independently without issue?  The "uTasker Support Demo and Simulation V1.4" document describes using the I2C interface, but does not mention (or give examples) using multiple I2C channels independently: usSpeed, TxQueueSize, RxQueueSize, Task_to_wake.  Also, will the simulator be able to handle simulating separate I2C devices?

Thank you.

4
The uTasker project uses definitions in application.c to enable specific features for testing:

#if !defined NO_PERIPHERAL_DEMONSTRATIONS
    #define _SPI_READ_CODE                                               // SPI reception checking
        #include "spi_tests.h"                                           // include SPI code to handle reception
    #undef _SPI_READ_CODE

    #define _I2C_READ_CODE                                               // I2C reception checking
    #if !defined BLAZE_K22
        #include "i2c_tests.h"                                           // include I2C code to handle reception
    #endif
    #undef _I2C_READ_CODE

    #define _ADC_POLL_CODE                                               // ADC polling operation
        #include "ADC_Timers.h"
    #undef _ADC_POLL_CODE

    #define _PORT_NMI_CHECK                                              // {53}
        #include "Port_Interrupts.h"                                     // port interrupt timer interrupt event handling - ranges
    #undef _PORT_NMI_CHECK
#endif

Specifically, the i2c_tests.h file has TEST_DS1307 defined.  When looking at the code in:
   1. Visual Studio, the code defined for TEST_DS1307 is enabled to be compiled and shown unghosted.
   2. Eclipse (MCUXpresso), the code defined for TEST_DS1307 is enabled to be compiled and shown ghosted.

Visual Studio does a good job of showing code in the editor that will be executed.  Eclipse does not do this for code included in the C source file with the definition defined in the C source file.

Is there a setting in Eclipse to make it work like it does in Visual Studio?  I believe the Eclipse Indexer is responsible for associating code and definitions viewed with the editor used in the application.  I have set the indexer with the following settings shown in the attachment.  I have been using both Visual Studio to help identify code that will be executed for the Eclipse during development, but would like eliminate this duplication and have Eclipse correctly show the executed code in the editor.

Tom

5
µTasker general / Re: My experience on Upgrading uTasker for the KE15Z
« on: November 22, 2019, 10:47:19 PM »
Thank you for the update, Mark.  I just pulled them into my latest uTasker project, built the executable, and FreeMASTER on the serial port is working well with your new changes to the LPUART0 ALT 6 configuration.

Regards,

Tom

6
Thank you, Mark for your recommendation on pulling the latest version.  I am new to GIT since we use SourceGear Vault at the company I work for.  I have found that GIT does make it very easy to update uTasker by doing a "git pull" on the latest commit.  My project directory is not affected by the pull since it is in the Untracked files.  Only the updated uTasker files will be replaced.

Tom

7
µTasker general / My experience on Upgrading uTasker for the KE15Z
« on: November 21, 2019, 10:40:19 PM »
Recently, I found that an issue with a task not being awakened after an I2C read call (see http://www.utasker.com/forum/index.php?topic=2047.0).  Since this issue was fixed since the build I started using for my project with uTasker, I thought it would be a good idea to use a later build that incorporated the changes I had found.  Created the following steps to upgrade my project.

Steps to Update
   1. Obtain the latest stable uTasker operating system.
   2. Unzip to a directory uTasker_latestStableBuild
   3. Create a MCUXpressoWorkspace directory
   4. Follow the uTaser instructions for creating the MCUXpresso integration of the workspace and project, but copy then import the present .cproject, .project, and .settings directory of the previous uTasker project.
   5. Copy all the .launch configurations and Revision History to the new project.
   6. Use WinMerge to find the differences.  Copy what is appropriate to recreate the project, the project directory located in the Applications directory.
   7. Clean and build the project.

I did this upgrade with uTasker_1.4.12.2019.11.15_11.40.37
After going through the "Steps to Update", on first build found that file CO_driver.h line 382, in structure definition CO_CANmodule_t had and unknown definition called QUEUE_HANDLE for CAN_interface_ID.  I found in the previous version of the file that I had, QUEUE_HANDLE was not used in CO_driver.h.    To work around this issue, I included file "types.h" since QUEUE_HANDLE is defined in this file:

#include "types.h"

Although, I did set up and build the uTaskerV1.4 project in MCUXpresso without my application code and it compiled without a problem for the FRDM_KE15Z.  I found that keeping the same Application files and importing the MCUXpresso project from the previous uTasker_1.4.12.2019.02.28 build did have one compiler problem.

After that change, the program would build, but when run, LPUART0 data was being ignored for our project.  Found that file kinetis.h did not have PA_2_LPUART0_RX and PA_3_LPUART_TX defined for PORT_MUX_ALT6 which is used in our project:

#define PA_2_LPUART0_RX           PORT_MUX_ALT6
#define PA_3_LPUART0_TX           PORT_MUX_ALT6

Found that kinetis_uart_pins.h is missing configuration of the LPUART0 port for PORT_MUX_ALT6.
Added after _CONFIG_PERIPHERAL(A, 2, (PA_2_LPUART0_TX | UART_PULL_UPS)), added line:

#elif defined KINETIS_KE15
            _CONFIG_PERIPHERAL(A, 3, (PA_3_LPUART0_TX | UART_PULL_UPS)); // LPUART0_TX on PA3 (alt. function 6)

Added after _CONFIG_PERIPHERAL(A, 1, (PA_1_LPUART0_RX | UART_PULL_UPS)), added line:

#elif defined KINETIS_KE15
            _CONFIG_PERIPHERAL(A, 2, (PA_2_LPUART0_RX | UART_PULL_UPS)); // LPUART0_RX on PA2 (alt. function 6)

I had added these definitions (see attachment files) on the previous version of uTasker and WinMerge helped identify some corrections I made to those uTasker driver level files.  The upgrade process was easy and went better than expected.  My conclusion is that uTasker is designed in a very modular which simplifies the process of upgrading your application code.

Tom

8
Hi Mark,

Thank you for identifying the difference in version I am using and a later one that you have coded to handle the repeated start condition.  Replacing the kinetis_LPI2C.h file with the newer one you provided fixed the missed uTaskerStateChange(ptrRxControl->wake_task, UTASKER_ACTIVATE).  My application is now working with both TASK_ALTITUDE_SENSOR and TASK_LED_DRIVER.

I did run into one compilation error on the kinetis_LPI2C.h file.  It looks like a new macro is used: WRITE_ONE_TO_CLEAR_INTERRUPT(ptrLPI2C->LPI2C_MSR, LPI2C_MSR_SDF, irq_id).  This one does not exist in my code version, so I replaced it with WRITE_ONE_TO_CLEAR(ptrLPI2C->LPI2C_MSR, LPI2C_MSR_SDF) and the code now compiles and executes with the desired result.

This leads me to the question of if it would be a good idea to update my version of uTasker to the latest in the GIT repository or do you have a specific version that you would recommend.  It might be a little effort on my part to merge my code into the latest version of uTasker, but if this will fix some behind the scene driver issues and not cause what has been working to fail, I will do it.  This missed scheduled task activation issue has cost me a few days of lost time while I try to understand the uTasker code and provide detailed enough observations for some assistance.  If you think using your a later version than uTasker_1.4.12.2019.02.28 for the Kinetis KE15Z processor then please let me know.

Thank you.

Tom

9
Thank you for your feedback, Mark.  The task, TASK_LED_DRIVER, does not use and fnRead() functions; it only uses fnWrite() and assumes the data was transferred.  The task TASK_ALTITUDE_SENSOR needs to read the altitude and temperature from the sensor, so it uses both fnRead() and fnWrite() commands.  Therefore, there should not be any confusion on which task was commanding the read, but  I think I have identified the source of the problem I am having.

Looking over the uTasker code, I think there is the possibility of a missed wake up owner of fnRead() task:
   1. A fnRead() takes place in TASK_ALTITUDE_SENSOR and changes the ucState to RX_ACTIVE and TX_ACTIVE in file kinetis_LPI2C.h line 358 of function fnTxI2C:
           I2C_tx_control[Channel]->ucState |= (RX_ACTIVE | TX_ACTIVE);
   2. The uTaskerStateChange(ptrRxControl->wake_task, UTASKER_ACTIVATE) does not happen until all bytes are transferred into the I2CPortID message queue in the interrupt handler function, fnI2C_Handler(), file kinetis_LPI2C.h:
   static void fnI2C_Handler(KINETIS_LPI2C_CONTROL *ptrLPI2C, int iChannel) // general LPI2C interrupt handler
   {
       I2CQue *ptrTxControl = I2C_tx_control[iChannel];
   
       if ((ptrLPI2C->LPI2C_MIER & ptrLPI2C->LPI2C_MSR) & LPI2C_MSR_SDF) {  // stop condition has completed
           fnLogEvent('S', ptrLPI2C->LPI2C_MSR);
           ptrLPI2C->LPI2C_MIER = 0;                                        // disable all interrupt sources
           WRITE_ONE_TO_CLEAR(ptrLPI2C->LPI2C_MSR, LPI2C_MSR_SDF);          // clear interrupt flag
           if ((ptrTxControl->ucState & RX_ACTIVE) != 0) {
               I2CQue *ptrRxControl = I2C_rx_control[iChannel];
               ptrRxControl->msgs++;
               if (ptrRxControl->wake_task != 0) {                          // wake up the receiver task if desired
                   uTaskerStateChange(ptrRxControl->wake_task, UTASKER_ACTIVATE); // wake up owner task
               }
           }
           else {
               if (ptrTxControl->wake_task != 0) {
                   uTaskerStateChange(ptrTxControl->wake_task, UTASKER_ACTIVATE); // wake up owner task since the transmission has terminated
               }
           }
           ptrTxControl->ucState &= ~(TX_WAIT | TX_ACTIVE | RX_ACTIVE);     // interface is idle
What I think is happening is that while the fnRead() communication on the physical I2C channel 0 is taking place, a fnWrite() command is called in task TASK_LED_DRIVER.  Calling fnWrite() will set the ptrTxControl->ucState to TX_ACTIVE and clear RX_ACTIVE before the " if ((ptrTxControl->ucState & RX_ACTIVE) != 0)" conditional is executed in the interrupt handler fnI2C_Handler().  If this happens, then the uTaskerStateChange(ptrRxControl->wake_task, UTASKER_ACTIVATE) statement will not happen.  This will cause the TASK_ALTITUDE_SENSOR not to wake up and handle the data read from the I2C in the I2CPortID buffer.

I have found that if I disable the TASK_LED_DRIVER, the returned data from the fnRead()s in TASK_ALTITUDE_SENSOR are handled, otherwise, the data is not handled because the TASK_LED_DRIVER is not scheduled to wake up.  By disabling TASK_LED_DRIVER, I can see that it does affect the wake up scheduling of TASK_ALTITUDE_SENSOR.  I checked the address of both where uState is set, line 358 in file kinetis_LPI2C.h, function fnTxI2C() :
       if ((ucAddress & 0x01) != 0) {                                       // reading from the slave
(358)         I2C_tx_control[Channel]->ucState |= (RX_ACTIVE | TX_ACTIVE);
           ptI2CQue->I2C_queue.chars -= 3;
           fnLogEvent('g', (unsigned char)(ptI2CQue->I2C_queue.chars));
           I2C_rx_control[Channel]->wake_task = *ptI2CQue->I2C_queue.get++; // enter task to be woken when reception has completed
           if (ptI2CQue->I2C_queue.get >= ptI2CQue->I2C_queue.buffer_end) {
               ptI2CQue->I2C_queue.get = ptI2CQue->I2C_queue.QUEbuffer;     // handle circular buffer
           }
       }
       else {
           I2C_tx_control[Channel]->ucState &= ~(RX_ACTIVE);
           I2C_tx_control[Channel]->ucState |= (TX_ACTIVE);                 // writing to the slave
           ptI2CQue->I2C_queue.chars -= (ptI2CQue->ucPresentLen + 1);       // the remaining queue content
           fnLogEvent('h', (unsigned char)(ptI2CQue->I2C_queue.chars));
       }
And where it is checked, line 135 in file kinetis_LPI2C.h, function fnI2C_Handler():
   static void fnI2C_Handler(KINETIS_LPI2C_CONTROL *ptrLPI2C, int iChannel) // general LPI2C interrupt handler
   {
       I2CQue *ptrTxControl = I2C_tx_control[iChannel];
   
       if ((ptrLPI2C->LPI2C_MIER & ptrLPI2C->LPI2C_MSR) & LPI2C_MSR_SDF) {  // stop condition has completed
           fnLogEvent('S', ptrLPI2C->LPI2C_MSR);
           ptrLPI2C->LPI2C_MIER = 0;                                        // disable all interrupt sources
           WRITE_ONE_TO_CLEAR(ptrLPI2C->LPI2C_MSR, LPI2C_MSR_SDF);          // clear interrupt flag
(135)          if ((ptrTxControl->ucState & RX_ACTIVE) != 0) {
               I2CQue *ptrRxControl = I2C_rx_control[iChannel];
               ptrRxControl->msgs++;
               if (ptrRxControl->wake_task != 0) {                          // wake up the receiver task if desired
                   uTaskerStateChange(ptrRxControl->wake_task, UTASKER_ACTIVATE); // wake up owner task
               }
           }
           else {
               if (ptrTxControl->wake_task != 0) {
                   uTaskerStateChange(ptrTxControl->wake_task, UTASKER_ACTIVATE); // wake up owner task since the transmission has terminated
               }
           }
           ptrTxControl->ucState &= ~(TX_WAIT | TX_ACTIVE | RX_ACTIVE);     // interface is idle

Both "I2C_tx_control[Channel]->ucState" and "ptrTxControl->ucState" point to the same location (0x200001CF) using the segger j-link debugger.  This tells me that it is possible that ucState can be changed before it is handled.  Was this the intention of uTasker I2C design?  If not, could you provide a solution (fix) that allows an I2C read to be handled even if another task is executing a I2C write?  My thought on a work around right now is to queue up all I2C reads and writes from the two tasks and handle them in one task that will allow only one fnRead() or fnWrite() command at a time until the task that commanded the read or write is woken.

Please let me know you thoughts.  I appreciate your feedback.

10
After reading the "uTasker - I2C Support, Demo and Simulation V1.4" document, I have two questions concerning uTasker task scheduling after an I2C read and write.:
Given the following information:
   There are two devices on the I2C bus: ALTITUDE_SENSOR and LED_DRIVER

   1. If one physical I2C channel is being used on the microcontroller that both ALTITUDE_SENSOR and LED_DRIVER are connected to, would more than one call be needed for fnOpen():?

void
configureI2CInterface (void)
{
    /*~~~~~~~~~~~~~~~~~~~~~~~*/
    I2CTABLE    tI2CParameters;
    /*~~~~~~~~~~~~~~~~~~~~~~~*/

    tI2CParameters.Channel = OUR_I2C_CHANNEL;
    tI2CParameters.usSpeed = 100;   // 100k
    tI2CParameters.Rx_tx_sizes.TxQueueSize = 64;    // transmit queue size
    tI2CParameters.Rx_tx_sizes.RxQueueSize = 64;    // receive queue size
    tI2CParameters.Task_to_wake = TASK_ALTITUDE_SENSOR;                // task to wake on transmission

    if((I2CAltitudeSensorID = fnOpen(TYPE_I2C, FOR_I_O, &tI2CParameters)) != NO_ID_ALLOCATED)
    {   // open the channel with defined configurations
        g_I2CAltitudeSensorIDIsActive = TRUE;
    }

    tI2CParameters.Task_to_wake = LED_DRIVER;                // task to wake on transmission

    if((I2CLedDriverID = fnOpen(TYPE_I2C, FOR_I_O, &tI2CParameters)) != NO_ID_ALLOCATED)
    {   // open the channel with defined configurations
        g_I2CLedDriverIDIsActive = TRUE;
    }

Then when a write takes place it is of the form:
   For ALTITUDE_SENSOR:
      bufferToWrite[] = { 0xc0, 0xfd, 0x0b };
      fnWrite(I2CAltitudeSensorID, (unsigned char *)bufferToWrite, sizeof(bufferToWrite));
      bufferToRead[] = {1, ALTITUDE_SENSOR_ADDR, TASK_ALTITUDE_SENSOR};
      fnRead(I2CAltitudeSensorID, (unsigned char *)bufferToRead, 0);
   
   For LED_DRIVER:
      bufferToWrite[] = { 0xe8, 0x00, 0x55 };
      fnWrite(I2CAltitudeSensorID, (unsigned char *)bufferToWrite, sizeof(bufferToWrite));
      bufferToRead[] = {1,LED_DRIVER_ADDR, TASK_LED_DRIVER};
      fnRead(I2CLedDriverID, (unsigned char *)bufferToRead, 0);
      
By setting up two handles: I2CAltitudeSensorID, I2CLedDriverID uTasker can wake the appropriate task when data is written and read.
   2. If what I proposed in question 1 is not true, how would I set up uTasker to make active the task when data is written and read given only one I2CPortID handle?

Right now I have one handle for both devices called I2CPortID.  The problem is that uTasker seems to not activate the task to handle fnRead() after the data has been read unless a breakpoint is inserted after the fnRead().  When a breakpoint is inserted after the fnRead(), the the proper I2C task will handle the buffer, otherwise the task will not become active.

Any ideas of how I should proceed?

11
µTasker general / Re: multiple fnInterruptMessage's
« on: November 18, 2019, 05:44:19 PM »
Thank you, Mark, for providing an alternate way to handle this situation.  I will take your advice and incorporate the changes in my code.

Regards,

Tom

12
µTasker general / Re: multiple fnInterruptMessage's
« on: November 16, 2019, 12:09:09 AM »
I have figured out what is happening.  uTasker will activate the task each time a new message is created.  If it happens that several messages are sent right after each other, only one of the activations for the task will occur.  To work around this, I read out all the messages sent into a two dimensional ucInputMessage array:

    // read out all the messages to be handled in this session
    numOfMessagesToHandle = 0;
    while(fnRead(PortIDInternal, ucInputMessage[numOfMessagesToHandle], HEADER_LENGTH))
    {
        if(++numOfMessagesToHandle > MAX_NUM_MSG_TO_HANDLE_FOR_TASK_ALT_TEMP_DRIVER)
        {
            errorCode.uTaskerTooManyAltTempMessages = TRUE;
         break;
        }
    }
 
After this, the code handles each of the messages in the ucInputMessage[][] array:

    for(index = 0; index < numOfMessagesToHandle; index++)
    {
           .....
     }

This solution will allow a task to handle all messages regardless of when they were sent allowing for the task to complete even if messages and timeouts are created within the handling task itself.  The issue with using a while loop on reading its message and handling it one at a time is it is possible for the handling task to create new messages to itself thereby not allowing the other tasks in uTasker operating system to have CPU time.  By leaving the handling task, other tasks will get CPU time and the handling task will be activated sometime after the other tasks have had CPU time.

13
µTasker general / Re: multiple fnInterruptMessage's
« on: November 14, 2019, 10:54:50 PM »
I have found that if I send multiple messages, one after the other, only the first message, INITIALIZATION, is recognized:

fnInterruptMessage(TASK_ALT_TEMP_DRIVER, INITIALIZATION);
fnInterruptMessage(TASK_ALT_TEMP_DRIVER, EV_ALARM_CONTROLLER_INITIALIZED);

I have looked through the uTasker documentation and cannot locate how to define a message queue large enough so that the second message, EV_ALARM_CONTROLLER_INITIALIZED, can be handled.  The task definition with the queue size is:

{"7_alt_temp_Driver",fnAltitudeTempDriver, LARGE_QUE,(DELAY_LIMIT)(NO_DELAY_RESERVE_MONO), 0, UTASKER_STOP}

I have noticed if that if the first message is sent and handled, then the second, both will wake the task, TASK_ALT_TEMP_DRIVER, and be read and handled correctly.

Any help would be appreciated.  Thank you.

14
I have determined why I am not getting the 10ms delay after it being set with fnConfigureInterrupt().  It is due to the architecture of the Kinetis KE part.

It was found that a timeout of the desired time TIMER_MS_DELAY(10) was occurring 16us (immediately after the fnConfigureInterrupt() call.  This interrupt time did not change when the desired interrupt time was changed.  Stepping through the code of fnConfigureInterrupt(), in file, kinetis_FlexTIMER.h, showed that bits FTM_SC_TOF and FTM_SC_TOIE were not being cleared/set.  The reason for this is due to incorrect bit mask definitions for  FTM_SC_TOIE and FTM_SC_TOF in file kinetis.h.  These two definitions need to be changed for a KE1xZ device according to their datasheet (see attachment).


In file kinetis.h, they are defined as
  #define FTM_SC_TOIE       0x00000040                                   // timer overflow interrupt enable
  #define FTM_SC_TOF        0x00000080                                   // timer overflow flag (write '1' to clear)
They need to be defined for KE1xZ devices as:
  #define FTM_SC_TOIE       0x00000100                                   // timer overflow interrupt enable
  #define FTM_SC_TOF        0x00000200                                   // timer overflow flag (write '1' to clear)

The other improvement that can be made is to add the present FTM_CNT to the FTM_MOD value since FTM_CNT is not zero after the first call to fnConfigureInterrupt().

Change from:
   ptrFlexTimer->FTM_MOD = ulDelay;

To:
   ptrFlexTimer->FTM_MOD = ptrFlexTimer->FTM_CNT + ulDelay;

Once this is done, the correct delay time will occur.


15
Thank you, Mark for your confirmation that the Kinetis part is compatible with the general purpose timer setup.

I set up the timer for a 10ms timer interrupt using:

timer_setup.int_handler = flexTimer1DelayIntHandler;
timer_setup.timer_value = TIMER_MS_DELAY(10);             // timer delay until interrupt

When I measure the time from the call to fnConfigureInterrupt((void *) &timer_setup) until the callbck_interrupt, flexTimer1DelayIntHandler, I measure exactly 16us on the oscilloscope.  Changing the value in the TIMER_MS_DELAY() (for example: 1000) does not change the 16us interrupt time.

I have stepped through the kinetis_FLEXTIMER.h code and noticed that after the iPrescaler is determined, the updated uDelay is directly assigned to the ptrFlexTimer->FTM_MOD register.  Should it not be assigned to "ulDelay+ptrFlexTimer->FTM_CNT" since the FTM_CNT cannot be assumed to be zero except after reset.  I changed this, but it had no effect in changing the 16us time in servicing the interrupt.

Do you have any suggestions on why I get such a short timeout?  I have gone through the program code and the iPrescaler, ulDelay, and assignments look correct for a 10ms timeout but what I measure on the oscilloscope shows this not to be true.
 

Pages: [1] 2