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

UART, ADC, BTLE, Timer 1msec

Currently working on an app which will utilize the ADC component of an NRF chip.

The app will use the full bluetooth stack SF132;6.0.0, adc, and will need to have ability to send uart.

First: I need to initialize the ADC for multiple channels and to not be triggered by a timer, but by the app.

Second: BLE will always be advertising/listening for a host device.

Third: UART will stream a small data packet ~10 Bytes, every second or so.

What do I need to do so that I can call the ADC read for all channels?

What would be the best way to get a 1msec tick, not a SysTick as I will need it to work even when the device is asleep.

How should the UART be initialized so that it will run even when the softdevice is handling btle packets?

Thanks.

Parents
  • Hi, 

    The SAADC driver documentation describes how you can trigger ADC sampling. Note that you have to trigger it via PPI if you want to sample all channels in quick succession (continuous mode), but you can still sample each channel only once per time it is triggered (see Scan mode). The most sensible way to trigger sampling every 1 ms is probably using the application timer (See timer library documentation). The SDK does not have any example that shows exactly this, but Jørgen has attached a project (zip file) to this post, which regularly samples two channels to this post. Note that it is for an older SDK and id uses the RTC directly instead of via the timer library, but most of the example should be relevant.

    The nRF52 only has a single CPU, so you cannot necessarily always have the UART peripheral running while the SoftDevice is handling a BLE packet. However, the UART peripheral has DMA support, so you may not need to use the CPU that much. Moreover, you should make sure to use hardware flow control if possible so that you do not risk losing data in case the nRF is not ready to receive data when the other UART device wants to transmit.

  • (continuous mode)

    Einar,

    I'm not sure how to setup the PPI to do this.

    What would I need to interconnect to sample all registered adc channels in quick succession?

    And how would I trigger the event to start this off without using a task specific interrupt.

    P.S. I've recently (last two hours) been informed that the ADC sample request could happen as fast as every 100 useconds.

  • Hi,

    From what I understood you want to sample multiple channels at the same time, but you want to trigger each series manually. Then you set up multiple channels to use scan mode, and trigger sampling of all channels by triggering the SAMPLE task once. This can be done from PPI (if you want a timer to do it), but as you wrote that you want to do it from the application you just have to write 1 to the SAMPLE task instead. Using the driver, this is typically done by calling nrf_drv_saadc_sample() after first calling nrf_drv_saadc_buffer_convert(), as described in the driver documentation. (You can also test with simply using nrf_drv_saadc_sample_convert() which is a blocking call that does everything in one go, but since it is blocking this is probably not sensible in a real application).

    If you mean that you in your project want to sample as fast as every 100 µs, then triggering sampling from the application (CPU) every time does not seem sensible. If so, you should use PPI instead. For that, I recommend you refer to the SAADC example in the SDK. It only uses one channel, but it does not need much adjustment to add another.

  • Einar, 

         That is a great post. My only real question left on ADC is, once all channels are initialized will the ADC read be triggered on all channels, or will I need to do some trickery in the adc handler?

    In addition, how will I know what channel was just read in the handler?

    Thanks for any help.

Reply Children
  • Hi,

    When you sample multiple channels using scan mode you only need to trigger sampling once. Then all channels will be sampled, and you will get a single event in the end. At that point you know that you have a new sample for each channel. The samples for all channels are put in the same buffer, but interleaved so that if e.g.  you have two channels, then you will find the samples for channel 1 in index 0,2,.. and for channel 2 in index 1,3,... Therefor the buffer size always has to be a multiple of the number of enabled channels (see driver doc).

  • Hi,

    Thanks for the clarification.

    The driver doc link points to the non-blocking mode of the SAADC configuration. However, the docs say this: 

    To enable the low power mode, you must specify this option when initializing the driver. You can do it by setting SAADC_CONFIG_LP_MODE to true in the driver initialization configuration structure. When it is enabled, the driver uses less power, but more interrupts are generated. When using this mode, the parameter size of function nrf_drv_saadc_buffer_convert must be a multiple of the number of enabled channels. Otherwise, undefined behavior may occur.

    Which I took to mean that the multiple of input channels, was only required for LP mode.

    I feel that a restructuring of that section of the docs would make this much easier to follow.

    Changing it so the content clearly says "[If running in scan mode, the dma buffer must be a multiple of the number of input channels.]"

    Also I'm not 100% familiar with successive approximation adcs, most of the ones I have dealt with just give me a "raw" value. Can I expect the same behavior from this configuration, or do I need to do any data manipulation to convert successive dma reads?

  • Hi,

    I agree that the documentation need a bit of improvement. Regarding the SAADC samples, you do not need to do any data manipulation other than adjust for the gain. However, you need to make sure that you set an acquisition time that is appropriate for your source (not too short if you have a high source resistance). You can refer to the SAADC electrical specification for details.

Related