Usage of ADC interrupt and the inner temperature sensor

Dependencies:   mbed-rtos mbed

Fork of rtos_basic by mbed official

Revision:
8:4d2d1dbbeda5
Parent:
7:84b7291a746d
--- a/main.cpp	Thu Jan 28 15:24:41 2016 +0000
+++ b/main.cpp	Thu Mar 31 14:13:20 2016 +0000
@@ -1,38 +1,71 @@
-/** 09_rtos_basic
- * RTOS LED blinking example running 3 threads
- * (main and two additional threads)
+/** 12_rtos_ADCinterrupt
+ * Using ADC interrupts and RTOS messaging for non-blockin waitting
+ * Meanwhile a LED is blinked...
+ * With our adc_read function we can reach extra 
+ * ADC channels as well, like the internal temperature sensor.
  *
  * Hardware requirement:
  *  - FRDM-KL25Z board
+ *  - Some analog voltage applied to A0 input
  */
 
 #include "mbed.h"
 #include "rtos.h"
- 
+AnalogIn adc(A0);
 DigitalOut led1(LED1);
-DigitalOut led2(LED2);
-DigitalOut led3(LED3);
- 
-void led2_thread(void const *args) {
-    while (true) {
-        led2 = !led2;
-        Thread::wait(2000);
-    }
-}
 
-void led3_thread(void const *args) {
-    while (true) {
-        led3 = !led3;
-        Thread::wait(4000);
-    }
-}
- 
-int main() {
-    Thread thread2(led2_thread);
-    Thread thread3(led3_thread);
-        
+typedef uint32_t message_t;
+Queue <message_t, 4> queue;
+
+void led1_thread(void const *args) {
     while (true) {
         led1 = !led1;
         Thread::wait(1000);
     }
 }
+
+//--- ADC Interrupt handler -----------------
+extern "C" void ADC0_IRQHandler()
+{
+    NVIC_ClearPendingIRQ(ADC0_IRQn);            //Clear ADC Interrupt Request Flag
+    uint16_t raw = ADC0->R[0];
+    queue.put((message_t*)raw);                 //Send result through a Queue
+}
+
+
+uint16_t adc_read(uint32_t ch) {
+    ADC0->SC3 = ADC_SC3_AVGE_MASK               // Hardware Average Enable
+              | ADC_SC3_AVGS(3);                // 32 Samples Averaged
+    // start conversion
+    ADC0->SC1[0] = ADC_SC1_AIEN_MASK | ch;      //Set channel, enable interrupt
+    osEvent evt = queue.get();                  //Wait for a message
+    return (uint16_t)evt.value.v;
+}
+
+int main() {
+/*
+ * The v25 value is the voltage reading at 25C, it comes from the ADC
+ * electricals table in the processor manual. V25 is in millivolts.
+ */
+    int32_t v25 = 716;
+
+/*
+ * The m value is slope of the temperature sensor values, again from
+ * the ADC electricals table in the processor manual.
+ * M in microvolts per degree.
+ */
+    int32_t m = 1620;    
+    NVIC_SetVector(ADC0_IRQn, (uint32_t)&ADC0_IRQHandler);      //Attach ADC interrupt service routine
+    NVIC_EnableIRQ(ADC0_IRQn);                                  //Enable ADC interrupt requests    
+    Thread thread1(led1_thread);
+
+    while (true) {
+        uint16_t a1 = adc_read(8);                              //Measure voltage at A0 (PTB0)
+        uint16_t a2 = adc_read(26);                             //Internal temperature sensor
+        float v1 = a1*3.3f/65536;                               //Convert v1 to Volts
+        float v2 = a2*3300.0f/65536;                            //Convert v2 to millivolts
+        float temp = 25.0f-(v2-v25)*1000.0f/m;                  //Calculate temp in Celsius                     
+        printf("A0 = %6.3f V  Temp = %5.2f C\n",v1,temp);
+        Thread::wait(2000);
+    }
+}