This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

Variable number of arrays - is this "dynamic memory"?



Colleagues,

I realize this is more of a c question than a TM4C one... or maybe at least an "embedded c". But I'll assume some good help can appear here.

Let's say I have a library created to deal with measuring a certain sensor. This sensor has parameters that could be organized together inside a struct called sensorStruct_t, such as:

typedef struct
{
    uint32_t sensor.outbase;
    uint32_t sensor.outpin;
    uint32_t sensor.inbase;
    uint32_t sensor.inpin;
    uint32_t sensor.readrate;
    float sensor.temperature;
    float sensor.humidity;
}
sensorStruct_t;

I find that most libraries for any similar purpose tend to have an "initialization" call. If I can live with the application having access to all elements of the sensor above, the initalization could be something like:

sensorStruct_t  sensorData1;
sensorInitialize(&sensorData1);

That is clean and organized. But I am unsure of how to manage a variable number of sensors...

One solution I've already used is to predetermine the maximum number of structures inside the library, and instead of passing a pointer from the application, to pass the actual parameters and have the library side manage some sort of "array of structures":

localSensor = sensorInitialize(outbase,outpin,inbase,inpin,readrate);

Where localSensor would just be the pointer to an address returned by the function. The initialize function adds the sensor to "the next available slot".

Again, might be c-programming class #12 (which I skipped), but I honestly don't know the best way to initialize "as many sensors as needed"... For now I've been actually creating a maximum quantity in the library side, and wasting the unused memory locations.

I hope this question is properly explained, as it did become a bit hard to make a clear point with a concise example... Any comments or guidance to specific literature are most welcome.

Regards

Bruno

  • Bruno Saraiva said:

    One solution I've already used is to predetermine the maximum number of structures inside the library, and instead of passing a pointer from the application, to pass the actual parameters and have the library side manage some sort of "array of structures":

    localSensor = sensorInitialize(outbase,outpin,inbase,inpin,readrate);

    Where localSensor would just be the pointer to an address returned by the function. The initialize function adds the sensor to "the next available slot".

    This is already dynamic memory. You've just written a specialized (pool) allocator.

    It's one of the safest forms of using allocation since the memory is allocated at compile time. The downside is the number of sensors were to exceed your maximum you cannot steal memory from another part of the application. For many embedded systems this is not much of a problem since you have to simultaneously handle all maximums in any case.

    Alternatively you can use malloc if you allocate everything on startup. This adapts well to different configurations w/o the need to invent multiple memory pools. As long as you only allocate and never free you have no fragmentation issues and as long as you do this once on startup you can only fail allocation in one place where you usually have the best reporting and safeing possibilities.

    Since you allocate for the maximum then you might be able to simply allocate by declaration instead. Not much advantage to dynamic allocation if you can just declare the sensor structure as part of the functionality that uses it.

    Rules

  • One question I didn't ask Bruno. Is this a run-time configurable number of sensors or is it known (or knowable) at compile time?

    If it's the latter then code generation is also a good solution. It might even be reasonable in the first case but that depends on specific details.

    Robert
  • Hello Robert,

    Thanks for both posts.

    The quantity of sensors is not known at compile time. The goal is to have one fixed firmware for a product, and the code initialization would somehow be able to check for the existence of sensors (maybe by HW polling, maybe by some external messaging...) Anyway, only AFTER the quantity of sensors is determined, the individual sensor initialization would occur.

    I guess that, in my case, allocating a maximum number of sensors inside the library won't be a problem. Even if the real structure consumes some 40 bytes, well... we could for now "waste" some 8x40 bytes in every compilation and let a maximum of 8 sensors to be initialized...

    One "future" concern is that we were thinking of creating the same kind of strategy for communication channels. We have succeeded to create decent libraries for serial comm, and the common library pre-allocates structures for 8 ports. In this case, things are even worse, for comm requires Tx and Rx buffers (yes, at the moment we allocate 8 Tx/Rx buffers even where only 1 pair of UART cables exist!). If we are to progress into using a common library for "any sort of communication", adding ethernet, usb, etc to the game, it certainly won't be wise to create/commit a huge number of buffers up front!

    But not to worry, I am just thinking out loud. This particular case would rather be implemented with the buffer declared on the application side, and maybe only the common parameters placed inside a "communication structure" on lib side. Further, when things get this complex, it is probably time to move on to a RTOS based solution!

    Cheers,

    Bruno

  • Bruno Saraiva said:
    The goal is to have one fixed firmware for a product

    Past firm & I thought of that - yet is not our field especially "Dynamic" - with new/improved devices regularly "bubbling up?"      

    How can "one fixed firmware" accommodate the, "Sure to arrive" future devices?     (the presence of which - may well "Drive further and higher value Sales!)

  • cb1, I'll need to rephrase it - a situation that's clear on writer's mind is not necessarily explained to readers miles away, as you well posted on the three-boards connection thread.

    Let me say I have three similar products based on the same board. We prefer to keep just one firmware for all three products, and somehow the MCU detects what "version" of the product is it dealing with, and behave accordingly. The description here of "one fixed firmware" is as opposed to managing three programs/projects, one for each of these "similar products".

    It does not mean it won't evolve or ever change - but as much as possible, we'd still upgrade just one firmware that is good for the different products.

    Among other things, one difference between such products is the quantity of sensors of a given kind. Hence, at compilation, the program must be able to work for either the simple one-sensor thing, as well as for the more expensive eight-sensors beast.

    Hope that makes more sense now! Cheers!
  • Bruno Saraiva said:
    Let me say I have three similar products based on the same board. We prefer to keep just one firmware for all three products, and somehow the MCU detects what "version" of the product is it dealing with, and behave accordingly.

    I've been using something similar myself (currently one board, one image, six uses). The single image and board means fewer items to track and stock. Differences are largely driven by static configurations, some hand written, some code generated. Works well given the large amount of memory available on these processors and the reasonably minimal processing needed for most of the applications.

    Robert

  • Bruno Saraiva said:
    One "future" concern is that we were thinking of creating the same kind of strategy for communication channels. We have succeeded to create decent libraries for serial comm, and the common library pre-allocates structures for 8 ports. In this case, things are even worse, for comm requires Tx and Rx buffers (yes, at the moment we allocate 8 Tx/Rx buffers even where only 1 pair of UART cables exist!). If we are to progress into using a common library for "any sort of communication", adding ethernet, usb, etc to the game, it certainly won't be wise to create/commit a huge number of buffers up front!

    Besides moving the buffer allocation further up the application, this may call for either a memory pool of buffers or startup allocation via malloc.

    Bruno Saraiva said:
    . Further, when things get this complex, it is probably time to move on to a RTOS based solution!

    Well before this point I think.

    BTW when you make that switch (probably before, you could use it now I suspect) take a look at RMA (Rate Monotonic Analysis). It's a lot simpler than it sounds and it's good knowing you have a firm foundation.

    Robert

  • Your case fully matches ours, to each and every word!
    One board and one firmware here can do things almost as different as measuring the speed of a train or the sugar level of a baking dough!
    Of course this is just an exaggeration, and products are highly related - but we manage it better this way. As long as we are careful enough not to destroy one product by changing some functionality on the other (somehow guaranteed by seriously isolating libraries).
    Bruno
  • Robert - assistez-moi, s'il vous plaît - can your, "Single board, one image, six uses" ... "properly" (i.e. quickly, somewhat easily) welcome and accommodate a newly added device - deemed, "Useful to the mix?"

    Might we limit this "newly added device" to the "non-trivial condition" - such that (some) non-standard (i.e. not predictable) new interface timings (even levels) must be accommodated by that "One image?"

    Would appreciate your views - especially "if" you've "faced - and overcome - this challenge."     Appreciate your forum efforts...

  • Robert Adsett said:
    take a look at RMA (Rate Monotonic Analysis)

    Will do, thanks!

    Return Material Authorization?   :)

  • Bruno - you are coming "perilously" close to "cb1 territory!"      (via including a 2nd definition (a more standard one (for "RMA")  we must note...)

  • Just sharing my "case study"...
    Having a firmware that worked fine for 3 products VERY similar products, the new #4 was based in the same hardware, but this one had quite different screen interactions, measured parameters and even usage "dynamics" (mode d'emploi).
    Adding the 4th functionality into existing code was actually MUCH EASIER/FASTER than the likely alternative exercise:
    - copy the existing project into a new one
    - locate and erase what is not related to the new product
    - implement new product's functionalities
    Regards
  • Bruno Saraiva said:
    Return Material Authorization?   :)

    There's a reason I spelled it out ;)

    You will find it referred to by the acronym though.

    Robert

  • "CRACK" Staff (too) quickly keyed in, "ARM" - searching upon "Monotonic" (there) yielded "interesting" results.     (they ARE masters of "mono-tone," though!)

  • Bruno Saraiva said:
    Adding the 4th functionality into existing code was actually MUCH EASIER/FASTER

    That may have been true - yet I doubt that truth can prove, "Universal."

    Most always (any) addition of new code will require an altered, "Test/Verify" protocol - and "more expansive code" may "breach" your (past) test/verify (and especially, Agency Approvals.)

    One size may (sometimes) fit all - but I would not "count on it" - and it is unlikely to be MUCH Faster/Easier...      As you surely know - so much hinges upon the Application - reasonably "simple" new App would dissolve your "much faster/easier" claim!     

    "Silver bullets" may be "For Sale" - yet they may not "always" work...

  • cb1_mobile said:
    Robert - assistez-moi, s'il vous plaît - can your, "Single board, one image, six uses" ... "properly" (i.e. quickly, somewhat easily) welcome and accommodate a newly added device - deemed, "Useful to the mix?"

    Certainly. A big part of it is the limited problem domain. It's basically a sensor actuator type of interface with some additional logic. So analog inputs, digital inputs, relay drivers, analog current loop outputs and RS-422 communicating over CAN (Bruno, we also use RMA scheduling for the CAN protocol definition). Multiple boards in a product.

    The analog inputs can be jumper configured to +/-10V or +/-20ma which covers the overwhelming majority of analog transmitters and a recent iteration added a couple of RTD inputs saving us the cost of RTD transmitters.

    A set of lookups determines input filtering, scaling, the translation of inputs to CAN messages and the translation CAN messages to outputs. As well some boards have additional processing. Which configuration and processes to use is determined by shunts or switches.

    So generally adding (or removing, which also happens) sensors is a matter of updating the tables. Updating the RS-422/485 involves more work. If you've prepared sufficiently in advance then changing scale for a new sensor may just involve an update to non-volatile memory w/o needing to update the application.

    This doesn't fit all applications but it works well for us. Even when we could cost optimize with a specific board, one or two of these general boards get us there faster.

    OTOH if I need to do something like add a quadrature encoder I won't be able to do it in this setup. A tachgen I could. I doubt I'll need either.

    Robert

  • Robert - great thanks - very illuminating - and nicely detailed.

    Especially noted is your cautionary, "Doesn't fit ALL applications" - yet the ability to, "Prove the concept (or not)" - and "Deliver on/ahead of promise date" indeed justifies your approach. (most of the time)

    As to your "quadrature encoder" - firm/I have (too often) noted difficulty to arise - especially when the encoder's location is either, "hostile or distant" from the (central) MCU."     In such cases - we (now) employ a (small) Cortex M0 (wide temp, robust version) - which manages the encoder and transmits (via RS422) back to the "master" MCU.     (in our case - often a Cortex M7)      Perhaps this method will "work for you" - AND extend your "One Board's" (External device accommodations!)

    Thanks again...

  • cb1_mobile said:
    Especially noted is your cautionary, "Doesn't fit ALL applications"

    Absolutely true but it does essentially describe much of the PLC and data acquisition domains. Speaking of which Bruno, if you want inspiration on how to set up for varying unknown sensors take a look at what PLCs do.

    I wouldn't use the approach for fan control on a range hood though.

    cb1_mobile said:
    Perhaps this method will "work for you" - AND extend your "One Board's" (External device accommodations!)

    That's the sort of thing we have the 422/485 interface for. Probably via Modbus RTU though.

    Robert

  • We thought so - small pin count M0s (which roam other than (TX) plains) - prove well up to the challenge of "massaging sensors and/or unexpected or "difficult" devices" into 422/485 compliance - to be passed on to your "One (master) board."

    Both the simplicity and range/robustness of these (past/dying) communication mediums surely challenge such (past/dying) labels.     And - in our field - (where messages are usually short) the "gain" yielded by the more complex/faster method may not (really) be noted...     (while extracting a long & demanding "learning curve" - often never truly "mastered.")

    Thanks again.