Project: LMT01 Temperature Sensor

This project displays up to three LMT01 temperature sensor readings in degrees C, reading one sensor at a time. The design allows for one LMT01 sensor per GPIO pin, and more can be easily added.

Example Output

testall ( only LMT01 sensors 1 and 2 are fitted )

Sensor-1: 25.5C or 77.9F
Sensor-2: 25.4C or 77.7F
Sensor-3: LMT01 faulty or disconnected
Sensor-4: No such sensor !!  ok.

The LMT01 Temperature Sensor

The LMT01 provides a digital output in the form of a pulse count that is transmitted by a train of current pulses.

After the LMT01 is powered up, it transmits a very low current of 34 µA for less than 54 ms while performing a temperature to digital conversion. When the temperature-to-digital conversion is complete, the LMT01 transmits a pulse train that toggles from the low current of 34 µA to a high current level of 125 µA.

The total pulse count represents the temperature of the LMT01.

LMT01 Spec

The LMT01 outputs at minimum 1 pulse and a theoretical maximum of 4095 pulses. Each pulse has a weight of 0.0625°C.

One pulse corresponds to a temperature less than 50°C while a pulse count of 4096 corresponds to a temperature greater than 200°C.

Warning

The LMT01 is only ensured to operate up to 150°C. Exceeding this temperature by more than 5°C may damage the device. The accuracy of the device degrades as well when 150°C is exceeded.

LMT01 TO-92 Package

_images/lmt01-mechanical.jpg

LMT01 Waveforms

Free Running Pulse Block Timing

Taken at the Collector of Q1

_images/lmt01-free-running-pulse-block-timing.png

Pulse Block Width

Taken at the Collector of Q1

_images/lmt01-pulse-block-width.png

Individual Pulse Timing

Taken at the Collector of Q1

_images/lmt01-pulses-expanded.png

The schematic

_images/f0-lmt01-temp-sensor-2.jpeg

LMT01 Software Flowchart

_images/f0-lmt01-temp-sensor.png

LMT01 Software

This is actually one file f0-lmt01-temp-sensor-2.fs but I’ve broken it up into three parts for clarity. If you copy and paste these files, just load part-1 first, part-2 second, and part-3 third.

Part-2

This is the ‘main’ program which counts the temperature sensor pulses, scales and prints the results.

: lmt01-fault? ( -- ) raw.temperature @ 0 = ;        \ If a sensor has a zero count, it's faulty
: pretty.print ( -- )  0 <# # 46 hold #s #> type  ;  \ Insert one decimal point into final value

: degrees.c ( raw -- C )  \ Print Degrees C
  pretty.print ." C "
;

: degrees.f ( raw -- F )  \ Convert Degrees C to Degrees F  (formula: °C  x  9/5 + 32 = °F
   90 5 / * 3200 + 10 /
   pretty.print ." F "
;

: degrees ( -- )
     lmt01-fault? if ." LMT01 faulty or disconnected "
        else
        raw.temperature @                      \ fetch total number of pulses counted
        10000 4096 */ 256 * 500000 - 1000 /    \ Temp (C) = ((count/4096) *256) -50 scale raw temp into degrees x 10
        dup degrees.c ." or " degrees.f
     then
;

: temperature? ( sensor -- )             \ one temperature? measurement
  0 lmt01-x.count !                      \ lmt01-x.count increments once per lmt01-x pulse
  0 raw.temperature !                    \ raw.temperature is lmt01-x.count total count
  0 ready.flag !                         \ ready.flag is set when raw.temperature value is stable and ready to be used
     case                                \ power up selected sensor
        1 OF lmt01-1.power.on ENDOF
        2 OF lmt01-2.power.on ENDOF
        3 OF lmt01-3.power.on ENDOF
        ." No such sensor !! " drop exit         \ sensor not implimented fall thru warning
     endcase
  green-on                               \ mark start of count window
  tim6_cr1_cen                           \ start timer6 (end of timer kills the power to the lmt01)
     begin                               \ loop until raw.temperature is stable
        pause
        ready.flag @ 1 =
     until
  degrees cr
;

: t temperature? ;

: testall cr ( -- ) \ simple test of sensors
  ." Sensor-1: " 1 t
  ." Sensor-2: " 2 t
  ." Sensor-3: " 3 t
  ." Sensor-4: " 4 t
;

Part-1

Contains all the low level routines, variables and constants

compiletoram

0 variable lmt01-x.count
0 variable raw.temperature
0 variable ready.flag

\ RCC Words
: rcc_apb2enr_syscfgen-set ( -- )  %1  0  lshift  rcc_apb2enr bis! ;   \ rcc_apb2enr_syscfgen syscfg clock enable
: rcc_apb1enr_tim6en ( -- ) %1 4 lshift rcc_apb1enr bis! ;             \ rcc_apb1enr_tim6en tim6 clock enable

: init.gpio ( -- )
  \ One Port pull up for all sensors
  rcc_apb2enr_syscfgen-set   \ REQUIRED!! for using GPIO's as interrupts!
  pull-up ( %xx -- ) 0 lshift gpioc_pupdr bis!  \ gpioc_pupdr_pupdr0 PC0
;

\ LMT01 related Words
: syscfg_exticr1_exti0 ( -- ) %0010  0  lshift  syscfg_exticr1 bis! ;  \ pc-0 is interrupt source  x010: pc[0] pin
: exti_imr_mr0-set ( -- )  %1  0  lshift  exti_imr bis! ;              \ exti_imr_mr0 set interrupt mask on line 0
: exti_pr_pr0 ( -- ) %1 0 lshift exti_pr bis! ;                        \ exti_pr_pr0    pending bit 0
: exti_ftsr_tr0-set ( -- )  %1  0  lshift  exti_ftsr bis! ; \ exti_ftsr_tr0 falling trigger event configuration of  line 0
: exti_pr_pr0-set ( -- )  %1  0  lshift exti_pr  bis! ;                \ exti_pr_pr0 interrupt pending flag for line 0
: nvic_iser_setena-exti0_1 ( -- )  %100000 0  lshift nvic_iser  bis! ; \ nvic_iser_setena-exti0_1
: nvic_icer_clrena-exti0_1 ( -- )  %100000 0  lshift nvic_icer  bis! ; \ nvic_icer_clrena-exti0_1

: lmt01-1.power.on  ( -- )
  output  ( %xx -- ) 2 lshift gpioc_moder bis!    \ gpioc_moder_moder1  PC1
  %1 1 lshift gpioc_bsrr bis!                     \ gpioc_bsrr_bs1; output high
;

: lmt01-2.power.on  ( -- )
  output ( %XX -- ) 4 lshift GPIOC_MODER bis!     \ GPIOC_MODER_MODER2  PC2
  %1 2 lshift gpioc_bsrr bis! ;                   \ gpioc_bsrr_bs2; output high


: lmt01-3.power.on  ( -- )
  output ( %XX -- ) 6 lshift gpioc_moder bic!     \ gpioc_moder_moder3  PC3
  %1 3 lshift gpioc_bsrr bis! ;                   \ gpioc_bsrr_bs3; output high


: lmt01-1.power.off %11 ( -- ) 2 lshift gpioc_moder bic! ; \ gpioc_moder_moder1  PC1
: lmt01-2.power.off %11 ( -- ) 4 lshift gpioc_moder bic! ; \ gpioc_moder_moder2  PC2
: lmt01-3.power.off %11 ( -- ) 6 lshift gpioc_moder bic! ; \ gpioc_moder_moder3  PC3

: lmt01-x.power.off ( -- ) \ turn off all lmt01's by switching the port from output to input mode
  lmt01-1.power.off
  lmt01-2.power.off
  lmt01-3.power.off
;

\ Tim6 related Words
48000000 constant fCK

: nvic_iser_setena-tim6 ( -- ) 1 17 lshift nvic_iser bis! ;     \ nvic_iser_setena   tim6
: nvic_icer_clrena-tim6 ( -- ) 1 17 lshift nvic_icer bis! ;     \ nvic_icer_clrena  tim6
: nvic_icpr_clrpend-tim6 ( -- ) 1 17 lshift nvic_icpr bis! ;    \ nvic_icpr_clrpend  tim6
: tim6_cnt@ ( -- ) tim6_cnt h@ ;  \ tim6_cnt_cnt   16 bit counter value
: tim6_cr1_opm ( -- ) %1 3 lshift tim6_cr1 hbis! ;      \ tim6_cr1_opm one-pulse mode
: tim6_cr1_cen ( -- ) %1 0 lshift tim6_cr1 hbis! ;      \ tim6_cr1_cen    counter enable
: tim6_cr1_cdis ( -- ) %1 0 lshift tim6_cr1 hbic! ;     \ tim6_cr1_cen    counter disable
: tim6_dier_uie ( -- ) %1 0 lshift tim6_dier hbis! ;    \ tim6_dier_uie        update interrupt enable
: tim6_sr_uif ( -- ) %1 0 lshift tim6_sr hbic! ;        \ tim6_sr_uif  clear tim6 int pending flag
: tim6_egr_ug ( -- ) %1 0 lshift tim6_egr hbis! ;       \ tim6_egr_ug  update generation

: preset.psc.no.int ( -- ) \ preset Prescaler but don't cause interrupt. PSC does not get 'active' until the second update event
  tim6_arr h!              \ preset arr
  tim6_egr_ug              \ update generation: (causes a interrupt when run) but loads ARR into shaddow register!
  tim6_sr_uif              \ clear tim6 int pending flag after running tim6_egr_ug
  tim6_dier_uie            \ update interrupt enable
;

: tim6.int.handler ( -- )
  nvic_icpr_clrpend-tim6              \ clear pending iser for tim6
  tim6_sr_uif                         \ clear tim6 int pending flag
  tim6_cr1_cdis                       \ counter disable
  nvic_icer_clrena-tim6               \ disable the tim6 interrupt or dropping power to the LMT01 will re-trigger it
  green-off                           \ mark finish of count window
  lmt01-x.power.off
  lmt01-x.count @ raw.temperature !   \ raw.temperature now contains valid lmt01 count
  1 ready.flag !                      \ it's safe to read raw.temperature now
  nvic_iser_setena-tim6               \ re-enable tim6 iser
  nvic_iser_setena-exti0_1            \ re enable exti0_1 iser ( won't work without this )
;

: init.tim6 ( -- )
  rcc_apb1enr_tim6en      \ enable tim6 in rcc
  tim6_cr1_opm            \ one pulse mode high = Counter stops counting at the next update event (clearing the bit CEN)
  47952 tim6_psc h!       \ preset prescaler for 1mS (47 for 1 uS)
  104 preset.psc.no.int   \ preset PSC --> clear int pending flag, enable interrupt
  ['] tim6.int.handler irq-tim6_dac !
  nvic_iser_setena-tim6   \ enable iser
;

: lmt01.interrupt.handler ( -- )
  exti_pr_pr0                         \ clear pending bit 0
  lmt01-x.count @ 1+ lmt01-x.count !  \ increment temperature count by one
  exti_pr_pr0-set                     \ clear external interrupt pending register (exti_pr)
;

: init.lmt01 ( -- )
  syscfg_exticr1_exti0                         \ negative going pulses from lmt01 trigger pc0 interrupt
  exti_imr_mr0-set                             \ exti0 set interrupt mask on line 0
  exti_ftsr_tr0-set                            \ falling trigger on line 0
  ['] lmt01.interrupt.handler irq-exti0_1 !    \ tie the interrupt handler to the interrupt
  nvic_iser_setena-exti0_1                     \ enable exti0_1 interrupt
;

Part-3

This last part adds initialization and multitasking

: main ( -- )                \ executed about every 5ms @48mHz
 pause
;

: init-general ( -- )        \ executed once at boot-up
  f0-disco-48mhz             \ switch MCU clock from 8 to 48 MHz
  init.gpio                  \ Initialisations
  init.tim6
  init.lmt01
;

task: maintask         \ essential multitasking Word
: main& ( -- )          \ multitasking.fs Word
  maintask activate    \ multitasking.fs Words
  begin main again     \ this is the only task, and it loops forever (about every 5uS @ 48Mhz clock) unless blocked
;

: init ( -- )        \ essential multitasking Word
  init-general      \ main user application inits
  multitask         \ multitasking.fs Word
  main&             \ multitasking.fs Word
;

init                 \ this init for non flash use, i.e. after uploading this program

Waveforms

Window Start to Pulse Block Start Timing

  • Window and Power are the same thing displayed on CH-1
  • Waveform 1: PC-1
  • Waveform 2: Collector Q1
_images/lmt01-pwr-up-delay.png

Pulse Block Start to Window Close Timing

  • Waveform 1: PC-1
  • Waveform 2: Collector Q1
_images/lmt01-pulseblock-window.close.png

Testall

  • Waveform 1: PC-1
  • Waveform 2: Collector Q1
_images/testall.png

Downloads

f0-lmt01-temp-sensor-2.fs

memmap.fs

bitfields.fs

template.xml

screen-f0-lmt01-temp-sens~2-cuaU0-498600-ctsrts.sh

Kernel be337881895e64e60016a3514a0dea8e.bin

be337881895e64e60016a3514a0dea8e.words.txt

be337881895e64e60016a3514a0dea8e.README.txt

lmt01.pdf

Note

The Kernel binary filename is a MD5SUM of the file itself.

md5 be337881895e64e60016a3514a0dea8e.bin
MD5 (be337881895e64e60016a3514a0dea8e.bin) = be337881895e64e60016a3514a0dea8e