This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

Share pin between SAADC and digital interface

Hi,

I'm using nRF52840 - QIAAD0 (it's revision 2 I think)
and nrfx_saadc API v2 (but I don't think it doesn't really matter here)

tl;dr
As stated in SAADC peripheral documentation "When enabled, the SAADC will acquire access to analog input pins specified in registers CH[n].PSELP and CH[n].PSELN" which is behaving exactly as expected. However when disabling SAADC (write 0 to ENABLE register) pins stays connected to SAADC peripheral. Everything looks like switch controlled by ANAEN signal (check schematics of GPIO pin details) still routes input signal to analog path and not digital part.

Is this expected behavior? 

Longer explanation and how to reproduce:
On my board I use the same pin for both analog signal and digital communication. During device operation program switches between reading analog value using SAADC and data transmission using UARTE.

What I noticed: When I measure input using SAADC and later switch to UARTE, communication fails.
I'm performing full initialization of peripherals every time so:

SAADC steps:
1. Set input (let's say AIN2/P0.04), configuration and buffers in SAADC.
2. Enable SAADC.
3. Sample input.
4. Disable SAADC.
Intermediate steps:
5. Configure in GPIO (the same - P0.04) pull-up and drive needed for further operation.
UARTE steps:
6. Set pin in uart config registers (again P0.04).
7. Configure rest of uart.
8. Enable uart.
9. Try to use it.

Pull-up is correctly applied in step 5, I see voltage on line rising to VDD level.
If I set this pin (P0.04) as UART TX I'm not seeing any transmission. Line stays constantly at VDD level.
If I set this pin (P0.04) as UART RX I'm seeing response from external device, but it's not received by peripheral.

Other observations:
  - On step 5. I tried toggling pin using GPIO peripheral with pull-up enabled. Line stayed all time on VDD level, not driving to low state (even in H0 drive).
  - I have also other analog channels on this device. If after measuring input on AIN2/P0.02 (after step 4.) I measure other channel, using same sequence of config->enable->measure->disable, I'm able to use serial communication or control pin using GPIO peripheral.
  - If I reset SAADC peripheral after disable step (4.) as explained in this post or similar to anomaly 212 workaround, I'm again able to use UARTE/GPIO.
  - If I clear configuration of SAADC pin and enable then disable peripheral (code below) I'm again able to use UART/GPIO.

NRF_SAADC->CH[0].PSELP = 0;
NRF_SAADC->CH[0].PSELN = 0;
NRF_SAADC->ENABLE = 1;
__NOP();
__NOP();
__NOP();
__NOP();
NRF_SAADC->ENABLE = 0;

  - Delays between steps 4, and 6. doesn't change anything.
  - When doing original steps (that results in UARTE not operating) I still can see exact moment when pin is configured in UARTE peripheral (pin number write to NRF_UARTE0->PSEL.TX) as slight change in voltage level on this pin. That looks like some internal switch working but not fully as intended.

My conclusion:
- SAADC has only "acquire pin" function implemented on enable but no function to return pins to digital on disable (or it's not working).

Is this indeed intended/expected behavior?
What safest or most elegant solution would you please suggest to switch pin back from analog path to digital?

Best regards
Tomasz

Parents
  • Hi,

    As far as I can see, the analog pins are acquired as soon as they are configured in the PSELP/PSELN registers, not when the SAADC->ENABLE register is set. Similar, the analog pins are released when the PSELP/PSELN registers are cleared.

    The comment in the ENABLE register documentation may thus be a bit inaccurate, as the ENABLE register does .

    Our SAADC driver clears the pin config in the uninit-function, and I would recommend you do the same in your application when you want to use the pins for digital peripherals.

    Best regards,
    Jørgen

Reply
  • Hi,

    As far as I can see, the analog pins are acquired as soon as they are configured in the PSELP/PSELN registers, not when the SAADC->ENABLE register is set. Similar, the analog pins are released when the PSELP/PSELN registers are cleared.

    The comment in the ENABLE register documentation may thus be a bit inaccurate, as the ENABLE register does .

    Our SAADC driver clears the pin config in the uninit-function, and I would recommend you do the same in your application when you want to use the pins for digital peripherals.

    Best regards,
    Jørgen

Children
  • Hi, thanks for an answer.
    It makes complete sense and also matches what I observed. Indeed docs are slightly misleading here.

    I'm using currently nRF SDK 17.1.0 which supports two nrfx_saadc implementations.
    Older one indeed clears channel configuration on uninit:

    nrf_saadc_disable();
    m_cb.adc_state = NRF_SAADC_STATE_IDLE;
    
    for (uint32_t channel = 0; channel < NRF_SAADC_CHANNEL_COUNT; ++channel)
    {
        if (m_cb.psel[channel].pselp != NRF_SAADC_INPUT_DISABLED)
        {
            nrfx_err_t err_code = nrfx_saadc_channel_uninit(channel);
            NRFX_ASSERT(err_code == NRFX_SUCCESS);
        }
    }


    However, the newer one (called API_v2) doesn't have it implemented:
    nrfx_saadc_abort();
    NRFX_IRQ_DISABLE(SAADC_IRQn);
    nrf_saadc_disable();
    m_cb.saadc_state = NRF_SAADC_STATE_UNINITIALIZED;


    To do it the way you suggest, I would have to call "nrfx_saadc_channels_config" with all previously used pins set to "NRF_SAADC_INPUT_DISABLED" and then uninit saadc which isn't really intuitive.

    As far as I see, nrfx_saadc implementation available on github has already "nrfx_saadc_channels_deconfig" implemented, which does exactly what is needed, however there is no information available that it needs to be called and it's also not automatically called on uninit.

    Maybe it will be good idea to write separate ticket for it, so it can be modified or better explained in future releases?

    Thanks again for help, I will implement it and give it a go.

    Best regards
    Tomasz

  • I have created internal tickets to look into peripheral documentation and clearing pins in nrfx_saadc_uninit_v2_api.

Related