Suspending a thread also suspends another randomly

Hello,

I've been working on a project using nRF52832 + NCS 2.1.1 including BLE and some sensors : MAX86150, MAX30205, MP34DT05, LIS3DH

I'm sending data of these sensors through BLE on demand i.e. requesting by sending a char code on a write characteristic for example to request PPG data (from MAX86150) I send 0x01 and for ECG (from MAX86150) I send 0x02. I have two separate threads one is the main thread (thread_main) which controls data requests, system and sensors shutdown, LED control and the other thread  (thread0):

void thread_main(void) {
	while(1) {
		// Check the input from client and manage the data send
		if (meas_value != 0xFF) {
			if (meas_value == 0x00) {
				printk("cancel any calculation\n");
				if (meas_value_current == 0x01) { 		// PPG + Force
					max86150_setPA_IR(&max86150_dev, 0);
					max86150_setPA_Red(&max86150_dev, 0);
					max86150_shutdown(&max86150_dev);
					suspend_thread0 = true;
				}else if (meas_value_current == 0x02) { // ECG
					max86150_shutdown(&max86150_dev);
					suspend_thread0 = true;
				}else if (meas_value_current == 0x03) { // PCG
					nrfx_pdm_stop();
				}else if (meas_value_current == 0x04) { // TEMP
					// max30205_shutdown(&max30205_dev);
					suspend_thread0 = true;
				}else if (meas_value_current == 0x05) { // Accel
					suspend_thread0 = true;
				}
				meas_value_current = 0xFF;
			}
			else if (meas_value == 0x01) {
				printk("cal PPG\n");
				MAX86150_config.slot[0] = MAX86150_SLOT_IR_LED1;
				MAX86150_config.slot[1] = MAX86150_SLOT_RED_LED2;
				MAX86150_config.slot[2] = 0;
				MAX86150_config.slot[3] = 0;
				MAX86150_config.IR_LED_PA = 0x1E;
				MAX86150_config.RED_LED_PA = 0x1E;
				max86150_init(&max86150_dev, &MAX86150_config, &MAX86150_data);
				// max86150_wakeup(&max86150_dev);
				k_timer_start(&thread0_timer, K_MSEC(1000), K_MSEC(0));
				meas_value_current = 0x01;
				wake_to_sleep_time = 0;
			}
			else if (meas_value == 0x02) {
				printk("cal ECG\n");
				MAX86150_config.slot[0] = MAX86150_SLOT_ECG;
				MAX86150_config.slot[1] = 0;
				MAX86150_config.slot[2] = 0;
				MAX86150_config.slot[3] = 0;
				MAX86150_config.ECG_sample_rate = ECG_SAMPLE_RATE_400;
				MAX86150_config.ECG_PGA_gain = ECG_PGA_GAIN_8;
				MAX86150_config.ECG_IA_gain = ECG_IA_GAIN_9_5;
				max86150_init(&max86150_dev, &MAX86150_config, &MAX86150_data);
				// max86150_wakeup(&max86150_dev);
				k_timer_start(&thread0_timer, K_MSEC(1000), K_MSEC(0));
				meas_value_current = 0x02;
				wake_to_sleep_time = 0;
			}
			else if (meas_value == 0x03) {
				printk("cal PCG\n");
				nrfx_pdm_start();
				meas_value_current = 0x03;
				wake_to_sleep_time = 0;
			}
			else if (meas_value == 0x04) {
				printk("cal TEMP\n");
				k_timer_start(&thread0_timer, K_MSEC(1000), K_MSEC(0));
				meas_value_current = 0x04;
				wake_to_sleep_time = 0;
			}
			else if (meas_value == 0x05) {
				printk("cal Accel\n");
				k_timer_start(&thread0_timer, K_MSEC(1000), K_MSEC(0));
				meas_value_current = 0x05;
				wake_to_sleep_time = 0;
			}
			else {
				printk("do nothing\n");
				meas_value_current = 0xFF;
			}
			meas_value = 0xFF;
		}

		// If disconnect condition is fulfilled, disconnect the BLE
		if (disconnect_ble) {
			printk("disconnecting ble\n");
			bt_conn_disconnect(my_conn, BT_HCI_ERR_REMOTE_USER_TERM_CONN);
			disconnect_ble = false;
		}

		// Put the lis3dh device to suspend mode
		if (lis3dh_drv_off) {
			printk("turning off lis3dh\n");
			pm_device_action_run(lis3dh_dev, PM_DEVICE_ACTION_SUSPEND);
		}

		// If system off condition is fulfilled, put it to the sleep mode
		if (system_off) {
			// turning off all leds if somehow one is on
			led_off(led_ind_pwm, 0);
			max86150_shutdown(&max86150_dev);
			

			printk("turning off the system\n");
			pm_state_force(0u, &(struct pm_state_info){PM_STATE_SOFT_OFF, 0, 0});
			k_sleep(K_SECONDS(2U));	
		}

		// Stop the measurement thread (thread0) whenever needed
		if (suspend_thread0) {
			printk("suspending thread0\n");
			k_thread_suspend(thread0_id);
			suspend_thread0 = false;
		}

		// Measure accelerometer to detect any inactivity
		struct sensor_value accel[3];

		sensor_sample_fetch(lis3dh_dev);
		sensor_channel_get(lis3dh_dev, SENSOR_CHAN_ACCEL_XYZ, accel);

		float x_accel_new = sensor_value_to_double(&accel[0]);
		float y_accel_new = sensor_value_to_double(&accel[1]);
		float z_accel_new = sensor_value_to_double(&accel[2]);

		if (abs(x_accel - x_accel_new) > 0.5 |
			abs(y_accel - y_accel_new) > 0.5 |
			abs(z_accel - z_accel_new) > 0.5)
		{
			wake_to_sleep_time = 0;
		}else{
			wake_to_sleep_time++;
			if (wake_to_sleep_time >= WAKE_DURATION) {
				k_timer_start(&before_system_off, K_MSEC(0), K_MSEC(0));
				wake_to_sleep_time = 0;
			}
		}
		x_accel = x_accel_new;
		y_accel = y_accel_new;
		z_accel = z_accel_new;

		// LED Pulsing
		if (led_pulsing) {
			led_on(led_ind_pwm, 0);
			k_msleep(50);
			led_off(led_ind_pwm, 0);
			k_msleep(50);
			led_on(led_ind_pwm, 0);
			k_msleep(50);
			led_off(led_ind_pwm, 0);
			k_msleep(50);
		}

		// Debug LED
		// gpio_pin_toggle_dt(&led_pin);
		printk("main loop running...\n");
		k_msleep(1000);

	}
}

The other thread (thread0) manages the data acquisition and sending of sensors (except for the PDM mic which has it's own callback):

void thread0(void) {
	while(1) {

		if (meas_value_current == 0x01) { // PPG + Force
			max86150_fetch_data(&max86150_dev, &MAX86150_config, &MAX86150_data);

			uint16_t ir_data = (MAX86150_data.channel_data[0]) >> 2;
			uint16_t red_data = (MAX86150_data.channel_data[1]) >> 2;

			float filtered_force = 0, sum_force = 0;
			float new_force = read_Force();
			force_array[force_idx++] = new_force;
			force_idx %= FORCE_WINDOW_SIZE;

			for (int j=0; j<FORCE_WINDOW_SIZE; j++) {
				sum_force += force_array[j];
			}
			filtered_force = (float)sum_force / FORCE_WINDOW_SIZE;
			

			// filtered_force = new_force;

			epf_buf[epf_count++] = red_data;
			epf_buf[epf_count++] = red_data >> 8;
			epf_buf[epf_count++] = ir_data;
			epf_buf[epf_count++] = ir_data >> 8;
			epf_buf[epf_count++] = 0;
			epf_buf[epf_count++] = 0;
			epf_buf[epf_count++] = (char) filtered_force;
			epf_buf[epf_count++] = (filtered_force - epf_buf[epf_count-1]) * 100;;
	
			if (epf_count >= EPF_BUF_SIZE) {
				send_notify(epf_buf, sizeof(epf_buf));
				epf_count = 0;
			}
			k_msleep(5);
		}
		else if (meas_value_current == 0x02) {// ECG
			max86150_fetch_data(&max86150_dev, &MAX86150_config, &MAX86150_data);

			int16_t ecg_data = (int16_t)(MAX86150_data.channel_data[0] >> 2);
				
			epf_buf[epf_count++] = 0;
			epf_buf[epf_count++] = 0;
			epf_buf[epf_count++] = 0;
			epf_buf[epf_count++] = 0;
			epf_buf[epf_count++] = ecg_data;
			epf_buf[epf_count++] = ecg_data >> 8;
			epf_buf[epf_count++] = 0;
			epf_buf[epf_count++] = 0;
	
			if (epf_count >= EPF_BUF_SIZE) {
				send_notify(epf_buf, sizeof(epf_buf));
				epf_count = 0;
			}
			k_msleep(5);
		}
		else if (meas_value_current == 0x04) {// Temperature
			float temp;
			uint8_t buf[2];

			// max30205_oneshot_read(&max30205_dev, &temp);
			temp = 32.5;

			buf[0] = (char) temp;
			buf[1] = (temp - buf[0]) * 100;

			send_notify(buf, sizeof(buf));
			k_msleep(1000);
		}
		else if (meas_value_current == 0x05) {// Accelerometer
			struct sensor_value accel[3];
			uint8_t buf[6];

			sensor_sample_fetch(lis3dh_dev);
			sensor_channel_get(lis3dh_dev, SENSOR_CHAN_ACCEL_XYZ, accel);

			float x_accel = sensor_value_to_double(&accel[0]);
			float y_accel = sensor_value_to_double(&accel[1]);
			float z_accel = sensor_value_to_double(&accel[2]);
			
			buf[0] = (char) x_accel;
			buf[1] = (x_accel - buf[0]) * 100;
			buf[2] = (char) y_accel;
			buf[3] = (y_accel - buf[2]) * 100;
			buf[4] = (char) z_accel;
			buf[5] = (z_accel - buf[4]) * 100;

			send_notify(buf, sizeof(buf));
			k_msleep(1000);
		}
		else {
			k_msleep(1000);
		}
	}
}

The thread_main is always running but the thread0 is suspended most of the time and is resumed on demand (when data is requested). As mentioned above, resuming and suspending thread0 is done in the thread_main. The problem is suspending thread0 is also sometimes suspending the thread_main. This happens very randomly and I haven't found any pattern to it's occurrence. I don't know exactly whats going on here. If I remove the k_thread_suspend(thread0_id) from thread_main loop and leave thread0 running forever (by having a 1000ms delay in it when there is nothing to do) then it won't occur anymore.I've attached the whole project file.

Thanks in advance,
Hossein

edit : The project file has been removed to convert this topic to public

Parents Reply Children
No Data
Related