Sensirion / embedded-uart-sps

Embedded UART Driver for Sensirion Particulate Matter Sensors - Download the Zip Package from the Release Page
https://github.com/Sensirion/embedded-uart-sps/releases
BSD 3-Clause "New" or "Revised" License
44 stars 24 forks source link

Atmel SAM4S implementation #55

Closed ambyc-fy closed 2 years ago

ambyc-fy commented 4 years ago

Hi I am struggling to get the sensor work with the Atmel Sam4s. I have verified UART comms works on a serial monitor and now connected the SPS30. I have also verified the serial communication is some how working because when i mess up the serial configuration the sensor int16_t sps30_probe(void); does not run.

Here are my observations.

First I run sps30_probe(). At some points it fails once but then it successfully probs.

I then set sps30_set_fan_auto_cleaning_interval_days which does not return an error and that is ok.

I then set sps30_start_measurement. Which reads ok. At this point I can hear the fan from the sensor.

The problem now comes on ret = sps30_read_measurement. To start with i get ret = -2 then next loop iteration i get ret = 0.

Can anyone help me please? Firstly to explain what is actually going on and secondly what i am doing wrong.

I am using the ASF library in Atmel Studio. The API is very easy to understand here http://asf.atmel.com/docs/latest/sam4c/html/group__buart__plc__group.html

Here is my main loop

int main (void)
{
    /* Insert system clock initialization code here (sysclk_init()). */

    sysclk_init();
    board_init();
    configUART();
    configTWI();
    adc_setup();
    SetupUART0();

    uint8_t uart0_i = 0, uart0_len;
    char uart0_buf[20];
    char ret_string[] = "";
    char pm_string[] = "";

    uint8_t len;
    char buf;

    struct sps30_measurement m;
    char serial[SPS30_MAX_SERIAL_LEN];
    const uint8_t AUTO_CLEAN_DAYS = 4;
    int16_t ret;

    while (sensirion_uart_open() != 0) {
        sendBTMessage("SEND 15 UART init failed\n\r");
        sensirion_sleep_usec(1000000); /* sleep for 1s */
    }

    sendBTMessage("SEND 15 UART opened\n\r");

    //sendBTMessage (" UART 1 Alive \n\r");
    /* Busy loop for initialization, because the main loop does not work without
     * a sensor.
     */
    while (sps30_probe() != 0) {
        sendBTMessage("SEND 15 SPS30 sensor probing failed\n\r");
        sensirion_sleep_usec(1000000); /* sleep for 1s */
    }

    sendBTMessage("SEND 15 SPS30 sensor probing successful\n\r");

    ret = sps30_set_fan_auto_cleaning_interval_days(AUTO_CLEAN_DAYS);
    if (ret) {
        sprintf(ret_string, "SEND 15 error %d setting the auto-clean interval\n\r", ret);
        sendBTMessage(ret_string);
    } else {
        sendBTMessage("SEND 15 fan stuff seem to be alright \n\r");
    }

    ret = sps30_start_measurement();
    if (ret < 0) {
        sendBTMessage("SEND 15 error starting measurement\n\r");
    } else {
        sendBTMessage("SEND 15 start measurement seem to be alright \n\r");
    }

    sendBTMessage("SEND 15 measurements started\n\r");

    /* Insert application code here, after the board has been initialized. */
    while (1) {
        sendBTMessage ("SEND 15 testing PM \n\r");

        ret = sps30_read_measurement(&m);
        sprintf(ret_string, "SEND 15 reading message ret %d \n\r", ret);
        sendBTMessage(ret_string);

        if (ret < 0) {
            sendBTMessage("SEND 15 error reading measurement\n\r");
        } else {
            if (SPS30_IS_ERR_STATE(ret)) {
                sprintf(ret_string, "SEND 15 Chip state: %u - measurements may not be accurate\n\r", SPS30_GET_ERR_STATE(ret));
                sendBTMessage(ret_string);
            }

            sprintf(pm_string, "SEND 15 measured values: 0.2f pm1.0, pm2.5 %0.2f, pm4.0 %0.2f, pm10.0 %0.2f, nc0.5 %0.2f, nc1.0 %0.2f, nc2.5 %0.2f nc4.5, %0.2f nc10.0, %0.2f typical particle size\n\r",
                    m.mc_1p0, m.mc_2p5, m.mc_4p0, m.mc_10p0, m.nc_0p5, m.nc_1p0,
                    m.nc_2p5, m.nc_4p0, m.nc_10p0, m.typical_particle_size);

            sendBTMessage(pm_string);

            sensirion_sleep_usec(1000000); /* sleep for 1s */
        }
    }
}

Here is my UART implementation.

int16_t sensirion_uart_select_port(uint8_t port) {
    return 0;
}

int16_t sensirion_uart_open() {
    return (buart_if_open(SERIAL_UART_0, 115200UL));
}

int16_t sensirion_uart_close() {
    return (buart_if_close (SERIAL_UART_0));
}

int16_t sensirion_uart_tx(uint16_t data_len, const uint8_t *data) {
    return buart_if_write (SERIAL_UART_0, data, data_len);
}

int16_t sensirion_uart_rx(uint16_t max_data_len, uint8_t *data) {
    return buart_if_read (SERIAL_UART_0, (uint8_t *) data, max_data_len);
}
void sensirion_sleep_usec(uint32_t useconds) {
    delay_us(useconds);
}
rnestler commented 4 years ago

First I run sps30_probe(). At some points it fails once but then it successfully probs.

It may be a timing issue. Could you try to wait a few 100ms before probing the first time?

The problem now comes on ret = sps30_read_measurement. To start with i get ret = -2 then next loop iteration i get ret = 0.

-2 is SENSIRION_SHDLC_ERR_MISSING_START according to sensirion_shdlc.h. So maybe your UART implementation misses the first byte? Or it has a timeout before the first byte arrives?

psachs commented 2 years ago

I close this issue, since there was no communication for a long time.