Recent Posts

Pages: [1] 2 3 ... 10
µTasker general / Re: Device doesn't retain low power configs
« Last post by Raffaele on March 02, 2021, 08:20:08 PM »
No worries about late reply Mark, thank you I appreciate your help.

Apparently there were three causes of error in my set-up: 1) as you pointed out, I needed to power cycle the board between programming it, 2) I had a signal analyzer connected to the board that was changing the absorbed current and gave inconsistent results, 3) I was trying to read an interrupt that was too short for the low power clock and the microcontroller wasn't able to catch it and it seemed like something stopped working.

µTasker general / Re: Device doesn't retain low power configs
« Last post by mark on March 02, 2021, 02:35:02 AM »

Sorry for not being able to respond earlier.

It may be that the open source version doesn't have all up to date low power control features but the thing to be aware of is that some of the low power registers are maintained across resets and some can only be written once after power on and any attempts to write them again with different values are ignored (also after a SW reset). Generally a power cycle is advised whenever something fundamental is change in a program.

Maybe this can explain something?

I checked the HW-related low power related code that I have in the Kinetis framework, which you can compare and check up on it the user's manual to see whether it helps explain or identify something:

Immediately after a reset:
        #if defined SUPPORT_LOW_POWER && (defined KINETIS_K_FPU || defined KINETIS_KL || defined KINETIS_REVISION_2 || (KINETIS_MAX_SPEED > 100000000))
            #if defined SUPPORT_LPTMR                                    // ensure no interrupts pending after waking from VLLS modes via LPTMR
    POWER_UP_ATOMIC(5, LPTMR0);                                          // power up the low power timer
    PMC_REGSC = PMC_REGSC_ACKISO;                                        // acknowledge the isolation mode to set certain peripherals and I/O pads back to normal run state
    LPTMR0_CSR = 0;                                                      // clear possible pending interrupt and stop the timer
    POWER_DOWN_ATOMIC(5, LPTMR0);                                        // power down the low power timer
    PMC_REGSC = PMC_REGSC_ACKISO;                                        // acknowledge the isolation mode to set certain peripherals and I/O pads back to normal run state

After a reset (but later):

    #if defined KINETIS_K_FPU || defined KINETIS_KL || defined KINETIS_KM || defined KINETIS_REVISION_2 || (KINETIS_MAX_SPEED > 100000000)
    SMC_PMPROT = SMC_PMPROT_LOW_POWER_LEVEL;                             // {117} - this may already have been written (with the same value) already during clock initialisation when HSRUN mode is used
    #elif !defined KINETIS_KE && !defined KINETIS_KEA
        #if !defined MC_PMPROT_LOW_POWER_LEVEL
            #define MC_PMPROT_LOW_POWER_LEVEL (MC_PMPROT_AVLP | MC_PMPROT_ALLS | MC_PMPROT_AVLLS1 | MC_PMPROT_AVLLS2 | MC_PMPROT_AVLLS3) // allow all low power modes if nothing else defined
    MC_PMPROT = MC_PMPROT_LOW_POWER_LEVEL;                               // {117}
    #if defined ERRATA_ID_8068 && !defined SUPPORT_RTC                   // if low power mode is to be used but the RTC will not be initialised clear the RTC invalid flag to avoid the low power mode being blocked when e8068 is present
    POWER_UP_ATOMIC(6, RTC);                                             // temporarily enable the RTC module
    RTC_TSR = 0;                                                         // clear the RTC invalid flag with a write of any value to RTC_TSR
    POWER_DOWN_ATOMIC(6, RTC);                                           // power down the RTC again


µTasker general / Re: Device doesn't retain low power configs
« Last post by Raffaele on February 26, 2021, 05:31:47 PM »
any help on what could cause the issue? Is it probably the fnLowPower task , but why would it work in one case (i.e., program device - turn off - turn on - reprogram) and not in the other (program - turn off - turn on)?

EDIT Update: I'm using some interrupt signals and it looks like my code gets stack when I inform that I want to enter VLPS (fnSetLowPowerMode(VLPS_MODE)). At that point, the task doesn't get activated any more when I use uTaskerMonoTimer('j', (DELAY_LIMIT) (5 * SEC), UTASKER_ACTIVATE);
µTasker general / Device doesn't retain low power configs
« Last post by Raffaele on February 23, 2021, 08:56:50 PM »

sorry if the title is misleading.
I'm having issues with programming a KL03. The code that I program the device with has a low power task that periodically moves from VLPW to VLPS, and vice versa.
If I:
Program the device -> Power it off -> Power it on again
Power it on -> Program with recompiled code (even the same exact code, just freshly recompiled)
 it stalls at the beginning (but I think neither in VLPW nor in VLPS, because the power consumption is larger than VLPW and lower than VLPS. I measured  the powers for each state).
Instead, if I:
Program the device -> Power it off -> Power it on -> RE-PROGRAM with the same code (not recompiled), then it works properly, and alternates between VLPW and VLPS.

What could it be?
My intuition is that during reprogramming something gets pulled high/low, probably for a certain amount of time necessary for my device to work properly.  And since this doesn't happen with a simple restart, the device/code gets stuck somewhere

NXPTM M522XX, KINETIS and i.MX RT / Kinetis CRC HW Module
« Last post by mark on February 21, 2021, 06:04:20 AM »
Hi All

The following details concern the CRC HW module in the Kinetis parts and is valid as from 21st Feb. 2021 in the developers version.

1. The driver can be enabled with (in app_hw_kinetis.h) SUPPORT_HW_CRC

2. These are the modes that are  implemented:

3. In debug.c are some test commands in the I/O menu which allow testing two CRC16 and two CRC32 types to be verified

    {"crc16",             "Check CRC-16-Maxim",                    DO_HARDWARE,      DO_CRC_16_MAXIM},
    {"crc16b",            "Check CRC-16-Buypass",                  DO_HARDWARE,      DO_CRC_16_BUYPASS},
    {"crc32",             "Check CRC-32-IEEE",                     DO_HARDWARE,      DO_CRC_32_IEEE},
    {"crc32m",            "Check CRC-32-Mpeg-2",                   DO_HARDWARE,      DO_CRC_32_MPEG2},

4. This is how to use it (see also the code in debug.c which verifies the result with reference values).

Code: [Select]
              static const unsigned char ucRefData[] = {'1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B'};

              fnCalculateCRC(ucRefData, sizeof(ucRefData), (CRC16_MAXIM_CALCULATION));   // configure the calculation and calculate the first buffer
              fnCalculateCRC(ucRefData, sizeof(ucRefData), 0);           // recalculate without reseeding
              ulCalculated = fnCalculateCRC(ucRefData, sizeof(ucRefData), 0); // recalculate without reseeding
              fnDebugHex(ulCalculated, (WITH_LEADIN | sizeof(unsigned short) | WITH_CR_LF)); // display the result
              if (ulCalculated == 0xf0bc) {                                // recalculate without reseeding and terminate (power down hardware CRC module)
              else {                 

Terminal output example:


The example shows the input being passed 3 times.
If one only needs to calculate a single buffer it is used like this:

Code: [Select]
usCalculated = (unsigned short)fnCalculateCRC(ucRefData, sizeof(ucRefData), (CRC16_MAXIM_CALCULATION));

CRC16_MAXIM_CALCULATION selects the standard to use (internally it uses 0x8005 polynomial, 0x0000 seed value and the result is inverted).
The result returned is always 32 bits in length but in the case of the CRC16 (as shown) it can be cast to a 16 bit result.

If the calculation is to be performed over multiple input buffers without resetting the seed in between following calls can be done with:

Code: [Select]
fnCalculateCRC(ucRefData, sizeof(ucRefData), (0)); // continue calculating the CRC over multiple buffers
fnCalculateCRC(ucRefData, sizeof(ucRefData), (0));
fnCalculateCRC(ucRefData, sizeof(ucRefData), (0));
usCalculated = (unsigned short)fnCalculateCRC(ucRefData, sizeof(ucRefData), (0)); // use the final result

The mode parameter is simply set to 0 so that the mode is retained without setting a new seed value. Intermediate results are returned but don't need to be used until all buffers have been handled.

5. After each calculation the CRC module is automatically powered down.

6. The API should be very easy to use and can be used for a wide range of standard CRC16 and CRC32 calculations just by passing the desired mode parameter (without needing to know all setup details to achieve the mode)

7. The function works in on the Kinetis HW when it has a CRC module integrated. It also works in the simulator when using this command. The simulator emulates the way that the module operates and produces the equivalent output for all of the modes.



µTasker general / How to extend CLI menus and commands in the uTasker application
« Last post by mark on February 19, 2021, 07:07:32 PM »
How to add new CLI menus and commands - valid from check-in 6th February 2021.

1. Add a new line in the table tMainCommand[]

    {"C",                 "Go to My Commands menu",                DO_HELP,          DO_MENU_HELP_MY_COMMANDS},

and add a new define DO_MENU_HELP_MY_COMMANDS (for example, see where the list with DO_MENU_HELP_MQTT is and add it on to there)

2. Search for the way that DO_MENU_HELP_MQTT is handled:

        else if (DO_MENU_HELP_MQTT == ucType) {
            ucMenu = MENU_HELP_MQTT;                                     // set MQTT menu
            return (fnDisplayHelp(0));                                   // large menu may require special handling

and add a new help handler for your new sub-menu:

        else if (DO_MENU_HELP_MY_COMMANDS == ucType) {
            ucMenu = MENU_HELP_MY_COMMANDS;                                     // set my new menu
            return (fnDisplayHelp(0));                                   // large menu may require special handling

Locate MENU_HELP_MQTT (it is an enum in versions from 6th Feb. 2021) and extend the list with MENU_HELP_MY_COMMANDS (this must be in the enum list menu_help_reference in the same order as the main menu is built up!!!!!).

3. Add a new line in the table



{ tMyCommands,          15, (sizeof(tMyCommands)/sizeof(DEBUG_COMMAND)),          "    My menu"},

Note that the value 15 is the tab spacing when listing commands in this menu. 15 tends to be fine but it can be increased if you have long commands in the menu (which are added next). See reference at the end to see what the TAB SPACING affects.

4. This then needs its own sub-menu (tMyCommands)

Start with

static const DEBUG_COMMAND tMyCommands[] = {
    {"up",                "go to main menu",                       DO_HELP,          DO_HELP_UP},
    {"help",              "Display menu specific help",            DO_HELP,          DO_MAIN_HELP},
    {"quit",              "Leave command mode",                    DO_TELNET,        DO_TELNET_QUIT},

so it supports basic help, quit and up commands.

This should already run, showing a sparse new sub-menu

5. To add a new command insert one in to the tMyCommands[] table

    {"new_command",              "Description",                  DO_MY_GROUP,      DO_MY_COMMAND},

where you need to add new defines

DO_MY_GROUP (see where the list with DO_TELNET is and add it to there)

DO_MY_COMMAND (start a new list of defines dedicated to the new sub-menu - eg. beginning with 1)

You can also use existing groups (such as DO_TELNET) if you want to handle the new command type there rather than creating a new group.

6. Make a group action handle (assuming a new group define was added) where the new command is handled - starting an action, with or without interpreting additional parameters passed in the ptrInput string)

static void fnNewGroup(unsigned char ucType, CHAR *ptrInput)
    switch (ucType) {
    case DO_MY_COMMAND:
        // Handle the command here

and enter it in

static int fnDoCommand(unsigned char ucFunction, unsigned char ucType, CHAR *ptrInput)

    case DO_TELNET:                  <----example of existing group handler
        fnDoTelnet(ucType, ptrInput);
    case DO_MY_GROUP:         <--- the new group handler
        fnNewGroup(ucType, ptrInput);


Now the new sub-menu exists, can be entered and exited and one new command is available. When the command is executed the DO_MY_COMMAND case is hit and the specific new command code can be added there.

     Main menu
N [TAB SPACING]Configure network
S              Configure serial interface
I              Go to I/O menu
A              Go to administration menu
O              Go to overview/statistics menu
U              Go to USB menu
M              MQTT client commands
C              Go to My Commands menu
help           Display menu specific help
quit           Leave command mode

     My menu
up             go to main menu
new_command    Description
help           Display menu specific help
quit           Leave command mode


To extend existing sub-menus with new commands just step 5. can be used to extend existing menus and no new group is usually needed.



µTasker general / Re: MCG_Lite Clock mode switching
« Last post by Raffaele on February 18, 2021, 04:33:14 AM »
Great, it all makes sense. It's working

Thank you
µTasker general / Re: MCG_Lite Clock mode switching
« Last post by mark on February 16, 2021, 10:21:41 PM »

I just checked and see that in fact moving between 2MHz and 8MHz LIRC is not allowed according to the user's manual. It says that there are shared clock generators involved and so passing through HIRC mode looks to be needed.
Just below the figure that you have shown is a list of registers to be written to do this.

To control the core and bus/flash clock speeds the register SIM_CLKDIV1 is written:
SIM_CLKDIV1 = (((SYSTEM_CLOCK_DIVIDE - 1) << 28) | ((BUS_CLOCK_DIVIDE - 1) << 16)); // prepare system and bus/flash clock divides
Ensure that when switching to a faster clock source that this is set for the new value before switching to the new, faster source to that the clocks are never too high (out of specification). You need to control this yourself since the default values are valid only for the main clock configuration -
you can define SYSTEM_CLOCK_DIVIDE_2 and BUS_CLOCK_DIVIDE_2 to be used in the alternative mode and write
SIM_CLKDIV1 = (((SYSTEM_CLOCK_DIVIDE_2 - 1) << 28) | ((BUS_CLOCK_DIVIDE_2 - 1) << 16));

The HIRC can be enabled in MCG_MC

MCG_MC |= MCG_MC_HIRCEN;        // this is optional and would allow the HIRC to run even when the processor is not working in HIRC mode

however it is enabled automatically when the HIRC is selected as clock source. I believe that it is disabled automatically too when a different clock source if selected when the enable bit is not specifically set, meaning that there is nothing to do if you want HIRC to be disabled when in the other mode.



µTasker general / Re: MCG_Lite Clock mode switching
« Last post by Raffaele on February 15, 2021, 08:46:37 PM »
Hi Mark,

yes my basic mode of operation is from the IRC48M. However, the only reason I start from IRC48M is because, as it appears from the MCG_Lite mode state diagram (see attached illustration) I can't go directly from LIRC8M to LIRC2M and viceversa, but I need to go to IRC48M first.
But from your answer 4 it looks like I'm wrong and I could go directly from  LIRC8M to LIRC2M (?)

1. If I understood correctly, the FCRDIV is set with the SLOW_CLOCK_DIVIDE as I can also see from this snippet of kinetis.h

Code: [Select]
      #elif defined RUN_FROM_LIRC
            #if defined RUN_FROM_LIRC_2M
                #define IRC_CLOCK      2000000
                #define IRC_CLOCK      8000000
            #if defined SLOW_CLOCK_DIVIDE
                #if (SLOW_CLOCK_DIVIDE == 1)
                    #define SLOW_CLOCK_DIVIDE_VALUE  (MCG_SC_FCRDIV_1)
                #elif SLOW_CLOCK_DIVIDE == 2
                    #define SLOW_CLOCK_DIVIDE_VALUE  (MCG_SC_FCRDIV_2)
                #elif SLOW_CLOCK_DIVIDE == 4
                    #define SLOW_CLOCK_DIVIDE_VALUE  (MCG_SC_FCRDIV_4)

 2. No, I don't plan to use peripherals, like UART, so I don't need LIRC_DIV2. But I'm using SPI, so I need BUS_CLOCK_DIVIDE.

So here are a couple of questions on the logic of OUTDIV1, OUTDIV4 and BUS_CLOCK_DIVIDE.
a) Do I just need to set a value for the main clock and BUS_CLOCK_DIVIDE and uTasker will automatically define the values for OUTDIV1 and OPUTDIV4?
b) If I switch from LIRC8M to LIRC2M, can I  (and if so, how?), change the values for  SLOW_CLOCK_DIVIDE, or BUS_CLOCK_DIVIDE? Since the clock is slower now, I might need to update them.

3. How can I disable IRC48M when I don't need it any more?

Yes I remember the issue with UART with slower clocks and you already helped me fix it  8)

µTasker general / Re: MCG_Lite Clock mode switching
« Last post by mark on February 13, 2021, 07:55:48 PM »

See the following for a practical guide to working with the MCG:
This is not the same as the MCG_Lite in the KL03 but the basic principles still apply.

I assume that your basic mode of operation is from the IRC48M and therefore the configuration (app_hw_kinetis.c) should be left for this, which will mean that the project is build for this mode and the processor will start in this mode.

To move from this mode to IRC8M the logical steps are:
1. Select 8MHz source using IRCS and prepare the divider value to be used (FCRDIV)
2. If you plan to use MCGIRCLK for some peripherals also adjust LICR_DIV2 to suit

At this point in time the system will still be operating from IRC48M but will be pre-prepared for the following mode

3. To perform the switch over CLKS is set to select the IRC8M output instead of IRC48M output (usually one spins on the status register checking that the switch-over has completed before continuing)
Now MCGOUTCLK is equal to 8Mz rather than 48MHz and all derived clocks (core, bus/flash) will be (at lest) 6x slower than before. In some cases OUTDIV1 and OUTDIV4 will now be changed to compensate (a little).
If you no longer need IRC48M it can be disabled now.

4. IRCS can be switched between 2MHz and 8MHz at any point whereby the resulting clocks (MCGIRCLK, Core, Bus/Flash) will switch 1/4 of the 8MHz speed and again some compensation may be performed.

When compensations are performed they can be performed 'after' the swith-over when the resulting speed is reduced.
When the resulting speed is increased compensations are usually performed 'before' the switch-over to ensure that the maximum output speed limites are respected during the process.
Whenever there is a status register showing the setting of a switch it should be polled to be the new value before continuing to ensure that the switch-overs have really completed before continuing.

Once the control registers and their control flags are known in the process the code is quite simple, as you have shown in your examples.

The most complicated thing is that when a new clock speed affects operating peripherals (such as UART) these will need to be set up with a new Baud rate value according to the new clock rate. This can lead to loss of data when switches are performed during operation and so such effects need to be carefully considered in the overall design. Specifially to the MCG_Lite that leaves IRC48M operating as clock source for peripherals in all modes, such peripheral speed are not effected by switch-overs to slower core, bus, flash speeds, which can simplify overall system design.


Pages: [1] 2 3 ... 10