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

Adding a multiplexer on SAADC Example - nRF52840 SDK16

Hi everyone,

I was looking at the SAADC example and I need to modify it in order to fit my design. I want to perform analog readings from eight sensors using an eight-channel multiplexer.

I will keep the timer/PPI arrangement and I want after each successful sample event to change MUX's channel in order to read the next sensor. What is the most efficient way of doing this?

I mean, is it possible to fill in the buffer with all sensors' values before saadc_callback(). If yes, how could I switch the MUX channel after each sampling event (I'm looking to sampling at 100Hz)?

One solution I can figure out is to define SAMPLES_IN_BUFFER 1 (to read only one sensor) and change the MUX's channel each time inside the saads_callback()..but.. it sounds like a dodgy business Slight smile

Any suggestions?

Thanks in advance

Nick

Parents
  • Why do you need to use an external mux? Can't you use the 8 analog input pins of the nRF52840? 

  • Hi haakonsh,

    Thanks for your reply. Yes, this could be an option but I would like to use the MUX as I want to have available the rest of the analog inputs for other tasks. Also, in the future is may be required to use a 16-channel MUX, so I have to work around with this solution...

  • Thanks for the guidance, I have some questions

    1. How do I enable the DONE event interrupt?

    2. Where do I find the ISR?

    You can then use a TIMER to manually trigger(not PPI) the SAADC's SAMPLE task to get the correct sample rate, and set the buffer to as many samples as you want. 

    3.1 Do you mean the app timer (RTC1) or the timer driver?

    3.2 Why should I avoid PPI?

    1. nrf_saadc_int_enable(NRF_SAADC_INT_DONE);

    2. nrfx_saadc_irq_handler() is found on line 102 in nrfx_saadc.c on nRF5 SDK 16.0.

      Inject an 
      if (nrf_saadc_event_check(NRF_SAADC_EVENT_DONE)){} on line 183.

    3.  
      1. Either a TIMER or an RTC, I'd choose an RTC with the RTC driver, f.ex RTC2. 

      2. Because the SoftDevice will block the SAADC ISR from executing during timing-critical radio events. If you do not get to execute the MUX change before the next SAMPLE task is triggered you've got at least one corrupt sample. Therefore you should call nrfx_saadc_sample() in the RTC drivers callback (or the app_timer callback). Since the SAADC ISR has execution priority over any application callback you're guaranteed to set the proper MUX settings before the SAMPLE task is triggered.
  • I just realized that we can control the MUX with a TIMER and 3 GPIOTE channels. 

    You'll need a TIMER set up as a counter, and have the SAADC's DONE event trigger the TIMER's COUNT task. This will increment the TIMER once for each of the SAADC's DONE events.

    The GPIOTE peripheral can toggle the state of a pin with an OUT task. We can then use the TIMER/COUNTER and GPIOTE to iterate through the MUX's truth table without any CPU activity at all.

    COMPARE event on COUNT = 1, Toggle ADD0
    COMPARE event on COUNT = 2, Toggle ADD0 and ADD1
    COMPARE event on COUNT = 3, Toggle ADD0
    COMPARE event on COUNT = 4, Toggle ADD0, ADD1, ADD2, and reset the COUNT to 0 by CLEARing the TIMER(this can be achieved through a SHORT where the last COMPARE event is coupled directly to the CLEAR task internally in the TIMER).

    This will create a truth table equal to the one in the MUX's datasheet.

    The PPI peripheral can fork any EVENT to one other TASK. For the fourth COMPARE event we'll need to set up somthing different to be able have the last COMPARE EVENT trigger the 3 GPIOTE TASKs.
    For that we need to use the Event Generator Unit. It's a simple peripheral where TASK[x] will trigger EVENT[x]. We can use EVENTs from the EGU to fork into other TASKs.

    F.ex: The TIMER's last COMPARE event triggers ADD0 toggle TASK, and through the forked event, trigger EGU TASK[0]. Then we fork(again) the EGU EVENT[0] to trigger the ADD1 and ADD2 toggle TASKs. This way the last COMPARE EVENT can trigger 3 TASKS.

    This will toggle MUX GPIOs at most 187.5ns after the SAADC's DONE event, with the MUX's switching time of 24ns you'll use at most ~210ns to switch the MUX, and you can therefore most likely, run the SAADC at 200ksps without issues.

  • Woo, too much information but it looks like a robust solution... I will try it and return with feedback.

    Also, I need a TIMER or RTC to trigger the SAADC's SAMPLE task, isn't it?

  • Yeah, I had to edit that post 6 times to make as "easy" to read as it is now. It's a bit abstract, but it is a good solution, especially at higher sample rates. Even at 100sps you will get a more reliable adc. 

    The RTC will have a lot of lower current consumption than a TIMER, but it has a minimum time resolution of 30.51µs. If you can use a multiple of 30.51µs then the RTC is the best option. 


Reply
  • Yeah, I had to edit that post 6 times to make as "easy" to read as it is now. It's a bit abstract, but it is a good solution, especially at higher sample rates. Even at 100sps you will get a more reliable adc. 

    The RTC will have a lot of lower current consumption than a TIMER, but it has a minimum time resolution of 30.51µs. If you can use a multiple of 30.51µs then the RTC is the best option. 


Children
No Data
Related