atsamd_hal/peripherals/calibration/
d11.rs

1//! NVM Software Calibration Area Mapping
2// For samd11, see 9.5 NVM Software Calibration Area Mapping, page 24
3// For samd21, see 10.3.2 NVM Software Calibration Area Mapping, page 46
4
5
6use atsamd_hal_macros::hal_cfg;
7use core::ptr;
8
9const ADDR: u32 = 0x806020u32;
10
11// Calculations for this from the datasheet values:
12// Example: Bit position: 41:37
13//
14// addr_offset = int(37/8) = 4
15// bit_shift = 37 % 8 = 5
16// Mask length = 41-37+1 = 5 bits (0b11111)
17fn cal(addr_offset: u32, bit_shift: u32, bit_mask: u32) -> u32 {
18    unsafe {
19        let addr: *const u32 = (ADDR + addr_offset) as *const _;
20        let value = ptr::read_unaligned(addr);
21
22        (value >> bit_shift) & bit_mask
23    }
24}
25
26fn cal_with_errata(
27    addr_offset: u32,
28    bit_shift: u32,
29    bit_mask: u32,
30    bad_val: u32,
31    def_val: u32,
32) -> u32 {
33    let val = cal(addr_offset, bit_shift, bit_mask);
34    // if the value matches the bad value, use an alternative value
35    // specified in the the errata section of the datasheet
36    if val == bad_val {
37        def_val
38    } else {
39        val
40    }
41}
42
43/// ADC Linearity Calibration. Should be written to ADC CALIB register.
44#[allow(clippy::unusual_byte_groupings)]
45pub fn adc_linearity_cal() -> u8 {
46    cal(3, 3, 0b11111111) as u8
47}
48
49/// ADC Bias Calibration. Should be written to ADC CALIB register.
50pub fn adc_bias_cal() -> u8 {
51    cal(4, 3, 0b111) as u8
52}
53
54/// Returns the osc32k calibration value from the NVM calibration area
55pub fn osc32k_cal() -> u8 {
56    cal(4, 6, 0b1111111) as u8
57}
58
59/// Returns the dfll48m coarse calibration value
60pub fn dfll48m_coarse_cal() -> u8 {
61    cal_with_errata(7, 2, 0b111111, 0x3f, 0x1f) as u8
62}
63
64/// USB TRANSN calibration value. Should be written to USB PADCAL register.
65pub fn usb_transn_cal() -> u8 {
66    cal_with_errata(5, 5, 0b11111, 0x1f, 5) as u8
67}
68
69/// USB TRANSP calibration value. Should be written to USB PADCAL register.
70pub fn usb_transp_cal() -> u8 {
71    cal_with_errata(6, 2, 0b11111, 0x1f, 29) as u8
72}
73
74/// USB TRIM calibration value. Should be written to USB PADCAL register.
75#[hal_cfg("nvmctrl-d11")]
76pub fn usb_trim_cal() -> u8 {
77    cal_with_errata(6, 7, 0b111, 7, 5) as u8
78}
79
80/// USB TRIM calibration value. Should be written to USB PADCAL register.
81#[hal_cfg("nvmctrl-d21")]
82pub fn usb_trim_cal() -> u8 {
83    cal_with_errata(6, 7, 0b111, 7, 3) as u8
84}
85
86// +0x10 offset below for all values as Temperature log row is at 0x00806030
87
88/// Room temperature in °C
89pub fn room_temp() -> f32 {
90    let int_val = cal(0x10, 0, 0b11111111);
91    let dec_val = cal(0x10 + 1, 0, 0b1111);
92    ((int_val * 10) + dec_val) as f32 / 10.0
93}
94
95/// Hot temperature in °C
96pub fn hot_temp() -> f32 {
97    let int_val = cal(0x10 + 1, 4, 0b11111111);
98    let dec_val = cal(0x10 + 2, 4, 0b1111);
99    ((int_val * 10) + dec_val) as f32 / 10.0
100}
101
102pub fn room_int1v_val() -> i8 {
103    cal(0x10 + 3, 0, 0b11111111) as i8
104}
105
106pub fn hot_int1v_val() -> i8 {
107    cal(0x10 + 4, 0, 0b11111111) as i8
108}
109
110/// 12-bit ADC conversion at room temperature
111pub fn room_temp_adc_val() -> u16 {
112    cal(0x10 + 5, 0, 0b111111111111) as u16
113}
114
115/// 12-bit ADC conversion at hot temperature
116pub fn hot_temp_adc_val() -> u16 {
117    cal(0x10 + 6, 4, 0b111111111111) as u16
118}