This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

comp or lpcomp for 2 analog inputs with different v-- (ref)

i am working with nrf52832

i need to check 2 analog inputs and set my own v- (ref) 

i can have value read every few seconds so no fast readings needs to be done 

if i understand correctly i better use lpcomp if no fast readings is needed?

also,  is it possible, and if there are some code examples, to be reading 2 analog inputs with 2 different v-- (references) (one for each input pin) ?

best regards

Ziv

Parents
  • Hello, 

    if i understand correctly i better use lpcomp if no fast readings is needed?

    Yes, Lpcomp is good for low-power readings of pin state changes. Have you seen the documentation for the LPCOMP peripheral, and the lpcomp example in the SDK?

    also,  is it possible, and if there are some code examples, to be reading 2 analog inputs with 2 different v-- (references) (one for each input pin) ?

    We have no examples demonstrating this directly, but you may modify the lpcomp example to use the external references on pins AIN0 and AIN1.
    Since the LPCOMP is only made to monitor one pin at the time, you will have to switch between the two pins and their references, to check the levels.

    Have you considered using the SAADC with differential ended input instead of the LPCOMP?
    Depending on your application, this might be both easier to implement and more precise.

    Best regards,
    Karl

  • thanks Karl

    since i can comp (or lpcomp) only one input pin each time and to switch between them i have to go through the handler and CPU anyway the COMP option in my case doesn't really helps

    i have started working on configuring and reading the 3 inputs pin with saadc driver, it is also not so easy, for example it is not possible to do OVERSAMPLING with multiple pins (aka SCAN MODE) (i did made a small change to the NRFX_SAADC.C file to achieve just that) but actually it is still not so clear to me how to manage the 3 inputs if i want to read each one of the in a different timing and is less CPU intervention as possible (i saw the saadc example with the timer and ppi but i am not sure how to manage that with 3 inputs, i have tried to look for a way to change the configured pin with in the saadc event handler but it fail) 

    if the saadc is kind of a new topic it is possible to close this post (i am not sure how to do that)

    best regards

    Ziv

  • Do I understand you correctly that you are intending to use the one SAADC channel to read the battery voltage of the device, and the two others to compare the pin levels to a reference?

    to be clear: 

    i want to use ont pin to read analog values of battery every few seconds. 

    on 2 other pins i have 2 optical sensors that gives analog inputs and i need to do something when each of them goes down from a ref v and up again.

    What I said in my last comment was that double sampling(having two PPI events trigger the SAMPLE TASK at the same time) is undefined behavior - meaning it is not specified what happens if this occurs. You could test it out and see, my guess is that one of the trigger events will be ignored(only 1 sample will occur).

    i can not take the risk of some event allwys or sometimes ignored, so this is not a vlide solution for me.

    you are configuring your channels are single ended inputs - instead of double ended? From earlier I think you said you wanted to use double ended(with an external reference?).

    i am planing to use some internal referance (some value i will hard code) not external.

     

    The DONE event will occur once the sampling completes. The LIMIT events may trigger whenever a new sample is gathered, that exceeds the limits. So the order would be DONE then LIMIT. You will get an event for each channel, if there are multiple LIMIT events.

    strange .. i read somewherer in this forom that the DONE event is triggered after data has been writen to RAM via easyDMA and the LIMIT event is triggered once the sempeled value exceeds a value in a register and this comparison happens before data is passed to the RAM hanse the LIMIT event will be triggered first.. is this wrong ?

    also, now when i use BURST and i read 3 channels is it a new event for each channel because it seems to be one call of the event handler for all 3 ? 

    another question is - is it possible to disable a certain limit event in the handler?  .. because after, for example, i got high limit event i don't want to get it again every read but i will want to enable it again once i get low limit event ?

    I would not recommend mixing HAL and driver function calls in your application, since this may unintentionally put the driver into an invalid state. What happens when you build and run the code you included above?

    not sure i allways know which functions are HAL and which drv 

    anyway and maybe it is related.. can i use the app_timer in my app and also the '

    nrf_drv_timer_t' timer (all exampels i saw that use ppi use the ' nrf_drv_timer_t ' but on other modules in my program i use the app_timer - which i guess picks the channel itself and i don't know which channel and can it be interfered with the ' NRF_DRV_TIMER_INSTANCE(channel); ' ?
    or is there any example on how to use ppi with app_timer ? 
    p.s. if i understand correctly from what you wrote and what i have read in the forom it is not a good idea to use the LPCOMP with 2 changing channels, sounless i missunderstood i am working on saadc only now (3 channels as i mentioned iand i guess i have no choice but to read them all at the same time ) 
    best regards
    Ziv
  • well i am trying to set a timer for saadc triggered via pi, i used app_timer in another module in my program but app_timer has no API to get saadc samle event address so ..

    i read the RTC0 is used by the softdevice and RTC1 is used by app_timer so i can use RTC2 for the 

    ' static const nrf_drv_timer_t m_timer = NRF_DRV_TIMER_INSTANCE(2); '

    but i get a compilation error - 

    'NRFX_TIMER2_INST_IDX' undeclared here (not in a function); did you mean 'NRFX_TIMER_INSTANCE'?

    /** @brief Macro for creating a timer driver instance. */
    #define NRFX_TIMER_INSTANCE(id)                                   \
    {                                                                 \
        .p_reg            = NRFX_CONCAT_2(NRF_TIMER, id),             \
        .instance_id      = NRFX_CONCAT_3(NRFX_TIMER, id, _INST_IDX), \
        .cc_channel_count = NRF_TIMER_CC_CHANNEL_COUNT(id),           \
    }
    
    #ifndef __NRFX_DOXYGEN__
    enum {
    #if NRFX_CHECK(NRFX_TIMER0_ENABLED)
        NRFX_TIMER0_INST_IDX,
    #endif
    #if NRFX_CHECK(NRFX_TIMER1_ENABLED)
        NRFX_TIMER1_INST_IDX,
    #endif
    #if NRFX_CHECK(NRFX_TIMER2_ENABLED)
        NRFX_TIMER2_INST_IDX,
    #endif
    #if NRFX_CHECK(NRFX_TIMER3_ENABLED)
        NRFX_TIMER3_INST_IDX,
    #endif
    #if NRFX_CHECK(NRFX_TIMER4_ENABLED)
        NRFX_TIMER4_INST_IDX,
    #endif
        NRFX_TIMER_ENABLED_COUNT
    };
    #endif

    i wonder why ???

    .. i have tried to edit the sdk_config file enableing 

    // <e> NRFX_TIMER_ENABLED - nrfx_timer - TIMER periperal driver
    //==========================================================
    #ifndef NRFX_TIMER_ENABLED
    #define NRFX_TIMER_ENABLED 1
    #endif
    // <q> NRFX_TIMER0_ENABLED  - Enable TIMER0 instance
     
    
    #ifndef NRFX_TIMER0_ENABLED
    #define NRFX_TIMER0_ENABLED 0
    #endif
    
    // <q> NRFX_TIMER1_ENABLED  - Enable TIMER1 instance
     
    
    #ifndef NRFX_TIMER1_ENABLED
    #define NRFX_TIMER1_ENABLED 0
    #endif
    
    // <q> NRFX_TIMER2_ENABLED  - Enable TIMER2 instance
    
    
    #ifndef NRFX_TIMER2_ENABLED
    #define NRFX_TIMER2_ENABLED 1
    #endif
    

    Best regards

    Ziv

  • hi Karl 

    one more question: 

    nrf_drv_saadc_limits_set(CHANNEL_IRRI_LEVEL, 1000, 1000);

    can i use the pin set like this .. where the limit high and limit low are of the same value and expect that when measured v goes below 1000mv then i will get a ' NRF_SAADC_LIMIT_LOW ' event

    and when measured v goes above 1000mv then i will get the ' NRF_SAADC_LIMIT_HIGH ' event ? 

    also i have noticed (not sure yet, i have to use some debug counters maybe) that i only get v limit event and no done event though i am waiting to read values in it from the other pin 

    best regards

    Ziv

  • i read somewherer in this forom that the DONE event is triggered after data has been writen to RAM via easyDMA and the LIMIT event is triggered once the sempeled value exceeds a value in a register and this comparison happens before data is passed to the RAM hanse the LIMIT event will be triggered first.. is this wrong ?

    to correct my comment -> the END (not DONE) event is triggered after data is writen to RAM .

    so i was wrong in my statement

    however, it brings a question to mind .. how many events are generated in each sample and if there are also channels set with limits what comes first and does some events gets lost or not triggered at all ???

  • Hello Ziv,

    ziv123 said:
    i can not take the risk of some event allwys or sometimes ignored, so this is not a vlide solution for me.

    That is totally understandable. As it is undefined behavior I am unable to confirm this particular behavior for you, and so you must either test it yourself or change the approach.

    ziv123 said:
    also, now when i use BURST and i read 3 channels is it a new event for each channel because it seems to be one call of the event handler for all 3 ? 

     I am not sure I understand what you mean here. As I have mentioned earlier, the SAADC only has 1 SAMPLE TASK, and when it is triggered it will sample all enabled channels. In your case, that means that it will sample all three channels each time the SAMPLE TASK is triggered. The event handler for the entire SAADC is the same one, as set up during the SAADC init.
    If this is not what you were asking about, please elaborate.

    ziv123 said:
    another question is - is it possible to disable a certain limit event in the handler?  .. because after, for example, i got high limit event i don't want to get it again every read but i will want to enable it again once i get low limit event ?

    I suppose you could just keep a variable for if the channel exceeded the high limit last time, and return from the callback immediately if a new LIMIT HIGH event is generated. If not, you would have to disable the channel to avoid generating the events all together, but then you would not know when it is back below the high limit again.
    As long as the channel is enabled, it will generate the event every time a sample comes in that exceeds its limits.

    ziv123 said:
    not sure i allways know which functions are HAL and which drv

    The HAL functions are prefaced by nrf_saadc, the legacy driver functions are prefaced by nrf_drv_saadc and the newest driver functions are prefaced by nrfx_saadc. You could see them all in the SAADC API Reference.
    Furthermore, there is nothing wrong with using those functions - many only use the HAL functions directly - or even program bare-metal - but I would recommend sticking to only one of the options, to avoid unexpected behavior. 

    ziv123 said:
    or is there any example on how to use ppi with app_timer ? 

    Please see this ticket.

    ziv123 said:
    p.s. if i understand correctly from what you wrote and what i have read in the forom it is not a good idea to use the LPCOMP with 2 changing channels, sounless i missunderstood i am working on saadc only now (3 channels as i mentioned iand i guess i have no choice but to read them all at the same time ) 

    I would have to agree, as it will require a lot of CPU interference, especially at high intervals. The LPCOMP peripheral is most commonly used to keep an eye on a reset button - or other very slow input.
    I absolutely think using the SAADC is right for your application, the more I heard about it.

    ziv123 said:
    however, it brings a question to mind .. how many events are generated in each sample and if there are also channels set with limits what comes first and does some events gets lost or not triggered at all ???

    My mistake, I seem to have misspoken. Since the SAADC events are all generated in the hardware, multiple events may be set when entering the callback handler. In that case, every set event will be handled in the same IRQ(if the callback is implemented as if(event), if(event) etc.). However, you will need to make sure that you are not staying in the IRQ for too long, so that a new event is generated before the old one is handled - this will lead to the new event going unnoticed, since the event is already set.

    ziv123 said:

    i wonder why ???

    .. i have tried to edit the sdk_config file enableing 

    Please make sure that the issue in this ticket is not the cause.

    ziv123 said:

    can i use the pin set like this .. where the limit high and limit low are of the same value and expect that when measured v goes below 1000mv then i will get a ' NRF_SAADC_LIMIT_LOW ' event

    and when measured v goes above 1000mv then i will get the ' NRF_SAADC_LIMIT_HIGH ' event ?

    I would think you can use it like this, but it will result in a limit event being generated every sample, either high or low. If this is not clear, please have another look at the SAADC LIMIT documentation.

    ziv123 said:
    i have noticed (not sure yet, i have to use some debug counters maybe) that i only get v limit event and no done event though i am waiting to read values in it from the other pin 

    Please elaborate what you mean here.

    Looking forward to solving this issue together, Ziv!

    Best regards,
    Karl

Reply
  • Hello Ziv,

    ziv123 said:
    i can not take the risk of some event allwys or sometimes ignored, so this is not a vlide solution for me.

    That is totally understandable. As it is undefined behavior I am unable to confirm this particular behavior for you, and so you must either test it yourself or change the approach.

    ziv123 said:
    also, now when i use BURST and i read 3 channels is it a new event for each channel because it seems to be one call of the event handler for all 3 ? 

     I am not sure I understand what you mean here. As I have mentioned earlier, the SAADC only has 1 SAMPLE TASK, and when it is triggered it will sample all enabled channels. In your case, that means that it will sample all three channels each time the SAMPLE TASK is triggered. The event handler for the entire SAADC is the same one, as set up during the SAADC init.
    If this is not what you were asking about, please elaborate.

    ziv123 said:
    another question is - is it possible to disable a certain limit event in the handler?  .. because after, for example, i got high limit event i don't want to get it again every read but i will want to enable it again once i get low limit event ?

    I suppose you could just keep a variable for if the channel exceeded the high limit last time, and return from the callback immediately if a new LIMIT HIGH event is generated. If not, you would have to disable the channel to avoid generating the events all together, but then you would not know when it is back below the high limit again.
    As long as the channel is enabled, it will generate the event every time a sample comes in that exceeds its limits.

    ziv123 said:
    not sure i allways know which functions are HAL and which drv

    The HAL functions are prefaced by nrf_saadc, the legacy driver functions are prefaced by nrf_drv_saadc and the newest driver functions are prefaced by nrfx_saadc. You could see them all in the SAADC API Reference.
    Furthermore, there is nothing wrong with using those functions - many only use the HAL functions directly - or even program bare-metal - but I would recommend sticking to only one of the options, to avoid unexpected behavior. 

    ziv123 said:
    or is there any example on how to use ppi with app_timer ? 

    Please see this ticket.

    ziv123 said:
    p.s. if i understand correctly from what you wrote and what i have read in the forom it is not a good idea to use the LPCOMP with 2 changing channels, sounless i missunderstood i am working on saadc only now (3 channels as i mentioned iand i guess i have no choice but to read them all at the same time ) 

    I would have to agree, as it will require a lot of CPU interference, especially at high intervals. The LPCOMP peripheral is most commonly used to keep an eye on a reset button - or other very slow input.
    I absolutely think using the SAADC is right for your application, the more I heard about it.

    ziv123 said:
    however, it brings a question to mind .. how many events are generated in each sample and if there are also channels set with limits what comes first and does some events gets lost or not triggered at all ???

    My mistake, I seem to have misspoken. Since the SAADC events are all generated in the hardware, multiple events may be set when entering the callback handler. In that case, every set event will be handled in the same IRQ(if the callback is implemented as if(event), if(event) etc.). However, you will need to make sure that you are not staying in the IRQ for too long, so that a new event is generated before the old one is handled - this will lead to the new event going unnoticed, since the event is already set.

    ziv123 said:

    i wonder why ???

    .. i have tried to edit the sdk_config file enableing 

    Please make sure that the issue in this ticket is not the cause.

    ziv123 said:

    can i use the pin set like this .. where the limit high and limit low are of the same value and expect that when measured v goes below 1000mv then i will get a ' NRF_SAADC_LIMIT_LOW ' event

    and when measured v goes above 1000mv then i will get the ' NRF_SAADC_LIMIT_HIGH ' event ?

    I would think you can use it like this, but it will result in a limit event being generated every sample, either high or low. If this is not clear, please have another look at the SAADC LIMIT documentation.

    ziv123 said:
    i have noticed (not sure yet, i have to use some debug counters maybe) that i only get v limit event and no done event though i am waiting to read values in it from the other pin 

    Please elaborate what you mean here.

    Looking forward to solving this issue together, Ziv!

    Best regards,
    Karl

Children
  • Hi Karl

     

    Well, so far I have managed to read the 3 channels in OVERSAMPLING with BURST enabled.

    I get the value of the battery in the event DONE type in the callback function and I get LIMIT event high or low for the 2 other channels once by disabling the high or low in the callback and enable them back when the opposite event is triggered

    (for some reason a value I am trying to change with in that handler does not change even when defined as 'volatile'  ???

    Some observations:

    1. I add counters to see how many times I enter each event before disabling the high and low events I got 2 LIMIT events followed by 1 DONE event . there maybe more event triggered but I do not monitor them within the saadc callback
    2. One time when I run the system with the ble and uart and some motors it suddenly changed from reading the battery channel to read one of the sensors (set_limit) channel.. I have no idea why and I did not manage to repeat that behavior.

    I would think you can use it like this, but it will result in a limit event being generated every sample, either high or low. If this is not clear, please have another look at the SAADC LIMIT documentation.

    If HIGH and LOW voltage are the same program will fail in initialization they have to be different

     

    Regarding the app_timer with ppi I have read that there is no api to get callback address in app_timer .. someone said it is possible to get it from cc register but I didn't really understood where to look for that and how to set it so I gave up on using ppi and considered that the sampling itself accurse in the background of the SW and the CPU is intervene only when sampling is done.

    maybe if i more efficiency will be required in the future i will reconsider going ppi on that 

    anyway, regarding the post you linked I am pretty sure I have only one sdk_config file but I will recheck it anyway to avoid the pain

     

    I can share parts of my code if it helps

    so other then finding out why my variable doesn't change from within the callback function and unless there will be some problems with the OVERSAMPLING and BURST afterall, this topic of saadc is done for me for now..  :) 

    best regards

    Ziv :) 

  • Hello Ziv,

    ziv123 said:
    Well, so far I have managed to read the 3 channels in OVERSAMPLING with BURST enabled.

    I am glad to hear your setup is working and that you are able to retrieve your samples!

    ziv123 said:
    (for some reason a value I am trying to change with in that handler does not change even when defined as 'volatile'  ???

    Could you tell me more about this value - where it is declared and how it is to be used?

    Are you trying to change the value of a variable you are passing into your function? In that case, you will need to pass it as a pointer(pass by reference) instead of its value(pass by value). The former will give you direct access to the variable's memory location, which you may then change. The latter only gives you a copy of the value at the time of reading, this copy will only exist within the scope of the function and is deleted at the return of the function.
    If the variable is declared within the function itself, you will need to use the 'static' keyword to indicate that the variable should not be reinitialized at every function call, and thus also not deleted at the end of each function call.
    The volatile keyword tells the compiler that the value of the variable might change at any time - independent of the program itself - such as the value of a register connected to a pushbutton, or other external trigger.

    ziv123 said:
    One time when I run the system with the ble and uart and some motors it suddenly changed from reading the battery channel to read one of the sensors (set_limit) channel.. I have no idea why and I did not manage to repeat that behavior.

    That sounds strange. Are you saying that the output from your VDD channel held the value of one of the other channels?

    ziv123 said:
    If HIGH and LOW voltage are the same program will fail in initialization they have to be different

    It is probably so to avoid the possibility that both events trigger at the same time, which would be nonsensical for a low or high detection. That seems reasonable, thank you for making me aware of it.

    ziv123 said:
    maybe if i more efficiency will be required in the future i will reconsider going ppi on that 

     I would highly recommend using the PPI feature - it is a very powerful peripheral to use for your embedded application. If you would like to see some bare-metal code regarding timer usage and setup, you may do so here. Additionally, I will also warn you about mixing bare-metal programming and the nrfx drivers, since this may place the drivers in invalid states.

    ziv123 said:
    anyway, regarding the post you linked I am pretty sure I have only one sdk_config file but I will recheck it anyway to avoid the pain

    The apply_old_config is a fallback, and is present in all the SDK examples by default.
    The trouble arise if you are setting *DRIVER*_ENABLED to 0 when disabling them, instead of commenting them out of the file entirely. This causes the *_ENABLED to be defined(even though it is disabled) which then applies the old config, overwriting the nrfx drivers.
    In essence: Comment out or remove unused defines in your sdk_config, do not set them to 0.

    ziv123 said:
    so other then finding out why my variable doesn't change from within the callback function and unless there will be some problems with the OVERSAMPLING and BURST afterall, this topic of saadc is done for me for now..  :) 

    Great, I am happy to hear that!
    If my above suggestions for the variable does not fix the issue, then you may open a new ticket for the issue. This sounds more like a C language issue than an nRF one, but I can help you resolve it if it persists - just make sure that you reference me in the ticket so that I will see it.

    Please do not hesitate to open a new ticket if you should encounter any other questions or issues in the future.

    Good luck with your development!

    Best regards,
    Karl

  • Are you trying to change the value of a variable you are passing into your function? In that case, you will need to pass it as a pointer(pass by reference) instead of its value(pass by value). The former will give you direct access to the variable's memory location, which you may then change. The latter only gives you a copy of the value at the time of reading, this copy will only exist within the scope of the function and is deleted at the return of the function.
    If the variable is declared within the function itself, you will need to use the 'static' keyword to indicate that the variable should not be reinitialized at every function call, and thus also not deleted at the end of each function call.
    The volatile keyword tells the compiler that the value of the variable might change at any time - independent of the program itself - such as the value of a register connected to a pushbutton, or other external trigger.

    i am familiar with all that .. i need to check if i get HIGH and LOW event one after the other for some reason

    basicaly the parameter is part of a globale instance of a struct

    That sounds strange. Are you saying that the output from your VDD channel held the value of one of the other channels?

    yes thats what i am saying, though i sisn't manage to repeat that fenomena again so i can not be sure what it means

    I would highly recommend using the PPI feature - it is a very powerful peripheral to use for your embedded application. If you would like to see some bare-metal code regarding timer usage and setup, you may do so here. Additionally, I will also warn you about mixing bare-metal programming and the nrfx drivers, since this may place the drivers in invalid states.

    like i wrote, right now i need the time it will take me to search for a way to use ppi with app_timer for other stufe like i2c and working with expander and nfc reader/writer (nxp) and also i could not find the beneffit of working with ppi if it calls for a handler that needs CPU anyway, if i understand corrctly the only thing that is different is that the ppi calls to the saadc handler without CPU and maybe the timer calls to the handler via its own handler so ther is one more call needing CPU    

    Best regards 

    Ziv

  • Hello again, Ziv

    All right - it sounds like you got it figured out, with your priorities in order.
    I am happy the issue is resolved and that you have the sought-after functionality up and running.

    Do not hesitate to open a new ticket if another issue should arise!

    Best regards,
    Karl

Related