cancel
Showing results for 
Search instead for 
Did you mean: 

control of 2 DAC and ADC converters, DAC81402 et ADS8691 with the STM32G431CBU

LIFER.1
Associate II

Hello at all

To do this, I use STM32CubeIDE and STMCubeMX to configure my I/O interfaces and serial buses, including two SPI buses to control my converters.
Only the hardware configuration of an SPI bus is limited to between 8 and 16 data buses, whereas my converters operate with between 24 and 32 bits of data...

However, in hardware SPI, my sync (CS) goes back after an 8- to 16-bit frame, whereas I need it to remain at 0 to meet the TI requirement.

So I tried to manage the sync pin in IO mode, but it still goes back...

I tried using DMA, but the CS signal delay I'm managing is too long before the start of my frame and ends long after it; I must be at about sixty microseconds, too long.

Note that I'm running my MCU at 24 MHz and I want to be able to retrieve my converted data in about 10 µS.

Currently, I'm using SPI bit bang, or I've configured my SPI port as IO, and I'm retrieving my values ​​in 212 µS, which is too long...

So, should I try assembler?...

Do you have any advice on this? A recommendation that could guide me to the best solution.

Thank you for your invaluable help.

Have a good day everyone.

11 REPLIES 11
LIFER.1
Associate II

In fact, with bit bang, I get this:

with Hardware SPI, i'm 54us, ... 

 

20250607_173244.jpg

 

I'm at a 54us frame rate, much better, but still not there. I configured the STM32CUBEMX to have an spi2 port with the CS (sync) pin as IO, but it takes a long time to respond...
Furthermore, my frames aren't close enough together; I have a latency between them that I can't reduce.

float ADS8691_ReadVoltageFast(uint8_t adc_num, float offset_correction)
{
    GPIO_TypeDef* sync_port;
    uint16_t sync_pin;

    if (adc_num == 1) {
        sync_port = ADC1_SYNC_GPIO_Port;
        sync_pin = ADC1_SYNC_Pin;
    } else {
        sync_port = ADC2_SYNC_GPIO_Port;
        sync_pin = ADC2_SYNC_Pin;
    }

    uint32_t nop = __REV(0x00000000);  // NOP command (32 bits)
    uint8_t rx_buf[4];

    // SYNC LOW
    sync_port->BSRR = (uint32_t)sync_pin << 16;

    // Envoyer NOP et recevoir 4 octets
    HAL_SPI_TransmitReceive(&hspi2, (uint8_t*)&nop, rx_buf, 4, HAL_MAX_DELAY);

    // SYNC HIGH
    sync_port->BSRR = sync_pin;

    // Reconstituer le mot reçu en little endian
    uint32_t raw = __REV(*(uint32_t*)rx_buf);

    // Extraire les 16 bits de conversion : bits 23:8
    uint16_t raw_code = (raw >> 8) & 0xFFFF;

    // Convertir en float : plage ±10.24V -> ±32768
    float voltage = ((int16_t)raw_code) * (10.24f / 32768.0f);

    // Appliquer la correction d’offset (ex: calibrage)
    return voltage + offset_correction;
}

 

 

 

 

LIFER.1
Associate II

20250607_174718.jpg

 

So, when I initialize my ADS8691, since it's only a write operation, can I send 32 clock pulses without latency?

void ADS8691_Init(uint8_t adc_num)
{
    GPIO_TypeDef* sync_port;
    uint16_t sync_pin;

    if (adc_num == 1) {
        sync_port = ADC1_SYNC_GPIO_Port;
        sync_pin = ADC1_SYNC_Pin;
    } else {
        sync_port = ADC2_SYNC_GPIO_Port;
        sync_pin = ADC2_SYNC_Pin;
    }

    uint32_t cmd = 0x40000000                             // CMD = Write Register
                 | ((uint32_t)(INPUT_RANGE_REGISTER & 0x3F) << 16) // Registre
                 | (uint32_t)(RANGE_BIPOLAR_10V24 & 0xFFFF);       // Valeur

    // SYNC LOW
    sync_port->BSRR = (uint32_t)sync_pin << 16;

    // SPI send 32 bits (MSB first)
    uint32_t tx = __REV(cmd);  // Reverse byte order for SPI transmission
    HAL_SPI_Transmit(&hspi2, (uint8_t*)&tx, 4, 10);

    // SYNC HIGH
    sync_port->BSRR = sync_pin;

    HAL_Delay(1);  // Optionnel
}