printid and get_temp implementation
[cortex-from-scratch] / drivers / tsensor.c
index d1ebcd4..079d309 100644 (file)
@@ -1,12 +1,29 @@
 /* (CC-BY-NC-SA) ROBIN KRENS - ROBIN @ ROBINKRENS.NL
  * 
  * $LOG$
- * 2019/8/4 - ROBIN KRENS      
- * PreInitial version 
+ * 2019/8/28 - ROBIN KRENS     
+ * Initial version 
  * 
  * $DESCRIPTION$
- * Temperature sensor 
- * [in dev]
+ * DS18B20 temperature sensor implementation
+ * Uses the 1-wire protocol. You will need to setup the temperature sensor
+ * with an external pull up resistor. High is the idle state of the chip.  
+ * This implementation does not use parasite power. Uses busy waits. 
+ * The chip doesn't require too accurate timings. Busy waits are between 15
+ * and 240 microseconds.
+ *
+ * The temperature conversion on the chip it takes a lot longer (up to 700ms).
+ * In case temperature is often read, implementing this with interrupts might be
+ * worthwile.
+ *
+ * Each series of commands is initiated with a long reset and prescence pulse.
+ * Implemented:
+ *     - Read ID of Chip
+ *     - Convert and read temperature
+ *
+ * TODO:
+ *     - Scratchpad copy functionality (+EEPROM)
+ *     - Alarm functionality
  *
  * */
 
 
 #include <drivers/tsensor.h>
 
-#define PRESCALER 36000 // 1 Mhz
-
-int *ccr1, *ccr2, *ccr1b, *ccr2b;
-bool s1, s2;
-
- void * update_handler() {
-
-/*     s1 = false;
-       s2 = false;
-       ccr1 = 0xFFFFFFFF;
-               ccr2 = 0xFFFFFFFF;
-               ccr1b = 0xFFFFFFFF;
-               ccr2b = 0xFFFFFFFF;
-       
-       if(rchkbit(TIM4_SR1, 1)) {
-                       s1 = true;
-               //      printf("CCR1: %p\n", *TIM4_CCR1);
-               //      printf("CCR2: %p\n", *TIM4_CCR2);
-                       ccr1 = *TIM4_CCR1;
-                       ccr2 = *TIM4_CCR2;
-                       rclrbit(TIM4_SR1, 1); 
-       }
-       
-       if(rchkbit(TIM4_SR1, 2)) {
-                       s2 = true;
-                       ccr1b = *TIM4_CCR1;
-                       ccr2b = *TIM4_CCR2;
-                       rclrbit(TIM4_SR1, 2);
-       }
-       
-       if(rchkbit(TIM4_SR1, 6)) {
-       //              printf("TRIGGER\n");
-                       rclrbit(TIM4_SR1, 6);
-       }
-
-       rclrbit(TIM4_SR1, 0);
-//     rclrbit(TIM4_SR1, 9); // OF
-//     rclrbit(TIM4_SR1, 10); // OF
+/* Commands */
+#define READ_ROM       0x33
+#define SKIP_ROM       0xCC
+#define READ_SCRATCH   0xBE
+#define CONVERT_T      0x44
 
-       // TODO clear overflow tag
-       
-       printf("SR1/CCR1: %p\n", ccr1);
-       printf("SR1/CCR2: %p\n", ccr2);
-       printf("SR2/CCR1: %p\n", ccr1b);
-       printf("SR2/CCR2: %p\n", ccr2b);
-
-       if (s1)
-               printf("EDGE DOWN\n");
-       if (s2)
-               printf("EDGE UP\n");
-
-       s1 = false;
-       s2 = false; */
-}
-
-static void reset() {
+/* Basic GPIO settings for output pulses and input */
+static void in_conf() {
        rwrite(GPIOB_CRL, 0x44444444);
 }
 
-void * tmp_update_handler() {
-
-       printf("SR: %p\n", *TIM4_SR1);
-       
-       rclrbit(TIM4_CR1, 0);   /* EMULATOR STOP */
-       rclrbit(TIM4_SR1, 0);
-       rclrbit(TIM4_SR1, 1);
-               reset();
-               tsensor_input(0xFFFF);
-
-//     if(rchkbit(TIM4_SR1, 1)) {
-//             printf("TEST\n");
-//     }
-
+static void out_conf() {
+       rwrite(GPIOB_CRL, 0x46444444); // open drain (with external pullup resistor)
 }
 
-void * cnt_complete_handler() {
-       rclrbit(TIM4_CR1, 0);
-       rclrbit(TIM4_SR1, 0);
-       rclrbit(TIM4_DIER, 0);
-       rwrite(GPIOB_CRL, 0x44444444);
-       printf("CNT COMPLETE\n");
-       tsensor_input(0xFFFF);
+/* Send command cmd over data wire. Each write slot should be
+ * at least 60ms.   */
+static void send_cmd(unsigned char cmd) {
+
+       int pos = 0;
+
+       for (int i = 0; i < 8; i++) {
+               // initiate write slot
+               out_conf();
+               rclrbit(GPIOB_ODR, 6); // pull low
+
+               // writing a logical 1 or 0 
+               if ((cmd >> pos) & 0x01) {
+                       _block(5);
+                       in_conf();
+                       _block(60);
+               }
+               else {
+                       _block(60);
+                       in_conf();
+               }
+               pos++;
+       }
 }
 
+/* Read reply of sensor. Depending on the command, the sensor
+ * can send back up to 9 bytes */
+static char get_byte() {
+
+       char c = 0x00;
+
+       for (int i = 0; i < 8; i++) {
+               /* Initate write slot*/
+               out_conf();
+               rclrbit(GPIOB_ODR, 6);
+               _block(3);
+               /* Listen for reply */
+               in_conf();
+               if (rchkbit(GPIOB_IDR,6)) {
+                       c = c | (0x1 << i);
+               }
+               else {
+                       c = c | (0x0 << i);
+               }
+               /* Each read slot should be at least 60 microseconds
+                * before the next one is initiated */
+               _block(60);
+       }
+       return c;
+}
 
-void tsensor_simple(uint16_t preload) {
-       
-       rsetbit(RCC_APB1ENR, 2); // TIM4 enable
 
-       rsetbitsfrom(TIM4_CR1, 5, 0x00); // edge-aligned mode
-       rclrbit(TIM4_CR1, 4); // upcounter (clrbit! not needed to set)
-       rsetbit(TIM4_CR1, 2); // only overflow generates update
+/* Initiate the sensor, send a reset pulse and wait consequently for 
+ * presence pulse. Slots should be at least 450 and 240 microseconds.  
+ * */
+static int tsensor_init() {
 
-       rwrite(TIM4_PSC, PRESCALER - 1);
-       rwrite(TIM4_ARR, preload);
-       rsetbit(TIM4_EGR, 0);
+       rsetbit(RCC_APB2ENR, 3); // GPIOB enable
+       
+       /* send presence pulse */
+       out_conf();     
+       rclrbit(GPIOB_ODR, 6); // pull low
+       _block(450);    
+       /* wait for the chips reply */
+       in_conf();
+       _block(60);
+       if (!rchkbit(GPIOB_IDR, 6)) {
+               //printf("Info: sensor detected\n");
+               //get_id();
+       }
+       else {
+               printf("Error: no temperature sensor found!");
+               return -1;
+       }
+       _block(240); // finish intialization slot
        
-       ivt_set_gate(46, cnt_complete_handler, 0);
-       rsetbit(NVIC_ISER0, 30); // interupt 41 - 32
+       return 0;
 
-       rsetbit(GPIOB_BSRR, 22); // 
-       rsetbit(TIM4_DIER, 0);
-       rsetbit(TIM4_CR1, 0);
+} 
 
-}
 
-void run() {
 
-       rsetbit(RCC_APB2ENR, 3); // GPIOB enable
-       rwrite(GPIOB_CRL, 0x47444444); // open drain general
 
-       rsetbit(GPIOB_BSRR, 22); // high
-       tsensor_simple(2000);
-//     tsensor_output(580, 520);
-//     reset();
-//     tsensor_simple(580);
+/* Wait for the chip to convert the temperature */
+static void wait_tconvert() {
+
+       printf("Info: Converting temp\n");
+       /* initiate write slot */
+       out_conf();
+       rclrbit(GPIOB_ODR, 6);
+       _block(3);
+       in_conf();
+       while (!rchkbit(GPIOB_IDR, 6)) {
+               //printf(".");
+               _block(60);
+               out_conf();
+               rclrbit(GPIOB_ODR, 6);
+               _block(3);
+               in_conf();
+       }
 }
 
-void tsensor_output(uint16_t preload, uint16_t compare/*, uint16_t pulses */) {
+/* Print some serial and CRC information about the chip */
+void tsensor_printid() {
 
-       /* GPIO AND CLOCK */
-       rsetbit(RCC_APB2ENR, 3); // GPIOB enable
-       rwrite(GPIOB_CRL, 0x4A444444); // PB6 for Channel 1 TIM4 alternate 
-       rsetbit(RCC_APB1ENR, 2); // TIM4 enable
-       
-       rsetbitsfrom(TIM4_CR1, 5, 0x00); // edge-aligned mode
-       rclrbit(TIM4_CR1, 4); // upcounter (clrbit! not needed to set)
-       rsetbit(TIM4_CR1, 2); // only overflow generates update
-
-       rwrite(TIM4_PSC, PRESCALER - 1); // 1 MHz
-       rwrite(TIM4_ARR, preload); // preload 
-       rwrite(TIM4_CCR1, compare); // compare
-       //rwrite(TIM4_RCR, pulses - 1); /* repeat ONLY IN ADVANCED TIMER */
-       
-       rsetbit(TIM4_EGR, 0); // update generation  
-       
-       rsetbit(TIM4_CR1, 3); // one pulse mode
-       rsetbitsfrom(TIM4_CCMR1, 4, 0x6); // mode
-       
-       //rsetbit(TIM4_CCMR1, 3); // preload enable
-       //rsetbit(TIM4_CR1, 7); // buffered
+       tsensor_init();
+       send_cmd(READ_ROM);
 
-       rsetbit(TIM4_CCER, 0); // enable output channeli 1
-       rsetbit(TIM4_CCER, 1); // active low
-       rsetbit(TIM4_CR1, 0); // start counter
+       // replies with 8 bytes
+       int nbytes = 8;
 
-       /* INTERRUPTS */        
-       ivt_set_gate(46, tmp_update_handler, 0);
+       char scratchbuf[nbytes];
+       memset(&scratchbuf, 0, sizeof(char) * nbytes);
+       scratchbuf[nbytes+1] = '\n';
+       
+       for (int i = 0; i < nbytes; i++) {
+               scratchbuf[i] = get_byte();
+       }
 
-       rsetbit(TIM4_DIER, 1);
-       rsetbit(NVIC_ISER0, 30); // interupt 41 - 32
        
+       printf("Family Code: %#x\n", scratchbuf[0]);
+       printf("Serial Number: 0x");
+       for (int i = 1; i < 7; i++) {
+               printf("%x", scratchbuf[i]);
+       }
+       printf("\n");
+       printf("CRC Code: %#x\n", scratchbuf[7]);
+
 }
 
-void tsensor_input(uint16_t preload) {
+/* Convert and read temperature of chip. Sensor has to be initialized twice
+ * since there are two series of commands (see datasheet flowchart) */
+uint16_t tsensor_get_temp() {
 
-       //uint16_t timestamp;   
-       /* GPIO AND CLOCK */
-       //rsetbit(RCC_APB2ENR, 3); // GPIOB enable
-       //rwrite(GPIOB_CRL, 0x44444444); // Input floating (default state)
-       //rsetbit(RCC_APB1ENR, 2); // TIM4 enable
-       
-       //rsetbitsfrom(TIM4_CR1, 5, 0x00); // edge-aligned mode
-       //rclrbit(TIM4_CR1, 4); // upcounter (clrbit! not needed to set)
+       /* initialize sensor and send commands */
+       tsensor_init();
+       send_cmd(SKIP_ROM);
+       send_cmd(CONVERT_T);
+       wait_tconvert();
 
-       rwrite(TIM4_PSC, PRESCALER - 1); // 1 MHz
-       rwrite(TIM4_ARR, preload); // preload 
+       tsensor_init();
+       send_cmd(SKIP_ROM);
+       send_cmd(READ_SCRATCH);
 
-       
-       rsetbit(TIM4_EGR, 0); // update generation  
+       /* Scratchpad is 9 bytes, but we are only interested in 
+        * the first two bytes, since they contain the LSB and 
+        * MSB of temperature  */
+       int nbytes = 2;
 
-       rsetbit(TIM4_CCMR1, 0); // input on TI1
-       rsetbit(TIM4_CCMR1, 9); // another input TI2
-       rsetbit(TIM4_CCER, 1); // other polarity for T1, inverted
+       char scratchbuf[nbytes];
+       memset(&scratchbuf, 0, sizeof(char) * nbytes);
+       scratchbuf[nbytes+1] = '\n';
+       
+       for (int i = 0; i < nbytes; i++) {
+               scratchbuf[i] = get_byte();
+       }
 
-       /* TODO: reg funct */
-       rsetbit(TIM4_SMCR, 4); // OLD: 101, new Edge detector
-       rsetbit(TIM4_SMCR, 6); // 
+       // LSB first four bits are after floating point
+       // uint8_t lsb_afltp = scratchbuf[0] & 0xF;
+        
+       int8_t lsb_bfltp = (scratchbuf[0] >> 4) & 0xF;
+       // MSB only the first three bits are used
+       uint8_t msb = scratchbuf[1] & 0x7;
+       
+       return  (msb << 4) + lsb_bfltp;
        
+}
 
-       // rsetbit(TIM4_SMCR, 2); // RESET rising edge triggers counter and generates update
-       rsetbit(TIM4_SMCR, 2); // OLD: 110
-       rsetbit(TIM4_SMCR, 1);
-       rsetbit(TIM4_SMCR, 0);
-       //rsetbit(TIM4_SMCR, 1); // 110
+/* 
+void test() {
 
-       //rsetbit(TIM4_CR1, 3); // one pulse mode // NOTE: RESET after finised preload
-       // will catch multiple signal... can set fram
-       
-       rsetbit(TIM4_CCER, 0); // enable capture channel 1 (changed pos)
-       rsetbit(TIM4_CCER, 4); // enable capture channel 2 
-       /* Caught on rising edge, no need to change*/
-       /* Clear capture event flag */
-//     rsetbit(TIM4_CR1, 0); // RESET with no trigger mode start
-
-       // enable capture channel 1 interrupt
-       rsetbit(TIM4_DIER, 1);
-       rsetbit(TIM4_DIER, 2);
-        ivt_set_gate(46, update_handler, 0);
-       rsetbit(NVIC_ISER0, 30);
+       //get_id();
+       uint16_t temp = get_temp();
+       printf("Current temperature: %d\n", temp);
 
-}
+} */