Chameleon-Mini
Codec.h
1 /*
2  * CODEC.h
3  *
4  * Created on: 18.02.2013
5  * Author: skuser
6  */
7 
8 #ifndef CODEC_H_
9 #define CODEC_H_
10 
11 #include <avr/io.h>
12 #include <stdint.h>
13 #include <stdbool.h>
14 #include "../Common.h"
15 #include "../Configuration.h"
16 
17 #include "ISO14443-2A.h"
18 #include "Reader14443-2A.h"
19 
20 /* Timing definitions for ISO14443A */
21 #define ISO14443A_SUBCARRIER_DIVIDER 16
22 #define ISO14443A_BIT_GRID_CYCLES 128
23 #define ISO14443A_BIT_RATE_CYCLES 128
24 #define ISO14443A_FRAME_DELAY_PREV1 1236
25 #define ISO14443A_FRAME_DELAY_PREV0 1172
26 #define ISO14443A_RX_PENDING_TIMEOUT 1 // ms
27 
28 /* Peripheral definitions */
29 #define CODEC_DEMOD_POWER_PORT PORTB
30 #define CODEC_DEMOD_POWER_MASK PIN0_bm
31 #define CODEC_DEMOD_IN_PORT PORTB
32 #define CODEC_DEMOD_IN_MASK (CODEC_DEMOD_IN_MASK0 | CODEC_DEMOD_IN_MASK1)
33 #define CODEC_DEMOD_IN_MASK0 PIN1_bm
34 #define CODEC_DEMOD_IN_MASK1 PIN2_bm
35 #define CODEC_DEMOD_IN_PINCTRL0 PIN1CTRL
36 #define CODEC_DEMOD_IN_PINCTRL1 PIN2CTRL
37 #define CODEC_DEMOD_IN_EVMUX0 EVSYS_CHMUX_PORTB_PIN1_gc
38 #define CODEC_DEMOD_IN_EVMUX1 EVSYS_CHMUX_PORTB_PIN2_gc
39 #define CODEC_DEMOD_IN_INT0_VECT PORTB_INT0_vect
40 #define CODEC_LOADMOD_PORT PORTC
41 #define CODEC_LOADMOD_MASK PIN6_bm
42 #define CODEC_CARRIER_IN_PORT PORTC
43 #define CODEC_CARRIER_IN_MASK PIN2_bm
44 #define CODEC_CARRIER_IN_PINCTRL PIN2CTRL
45 #define CODEC_CARRIER_IN_EVMUX EVSYS_CHMUX_PORTC_PIN2_gc
46 #define CODEC_CARRIER_IN_DIV 2 /* external clock division factor */
47 #define CODEC_SUBCARRIER_PORT PORTC
48 #define CODEC_SUBCARRIER_MASK_PSK PIN4_bm
49 #define CODEC_SUBCARRIER_MASK_OOK PIN5_bm
50 #define CODEC_SUBCARRIER_MASK (CODEC_SUBCARRIER_MASK_PSK | CODEC_SUBCARRIER_MASK_OOK)
51 #define CODEC_SUBCARRIER_TIMER TCC1
52 #define CODEC_SUBCARRIER_CC_PSK CCA
53 #define CODEC_SUBCARRIER_CC_OOK CCB
54 #define CODEC_SUBCARRIER_CCEN_PSK TC1_CCAEN_bm
55 #define CODEC_SUBCARRIER_CCEN_OOK TC1_CCBEN_bm
56 #define CODEC_TIMER_SAMPLING TCD0
57 #define CODEC_TIMER_SAMPLING_CCA_VECT TCD0_CCA_vect
58 #define CODEC_TIMER_SAMPLING_CCB_VECT TCD0_CCB_vect
59 #define CODEC_TIMER_LOADMOD TCE0
60 #define CODEC_TIMER_LOADMOD_OVF_VECT TCE0_OVF_vect
61 #define CODEC_TIMER_LOADMOD_CCA_VECT TCE0_CCA_vect
62 #define CODEC_TIMER_LOADMOD_CCB_VECT TCE0_CCB_vect
63 #define CODEC_TIMER_LOADMOD_CCC_VECT TCE0_CCC_vect
64 #define CODEC_TIMER_MODSTART_EVSEL TC_EVSEL_CH0_gc
65 #define CODEC_TIMER_MODEND_EVSEL TC_EVSEL_CH1_gc
66 #define CODEC_TIMER_CARRIER_CLKSEL TC_CLKSEL_EVCH6_gc
67 #define CODEC_READER_TIMER TCC0
68 #define CODEC_READER_PORT PORTC
69 #define CODEC_READER_MASK_LEFT PIN0_bm
70 #define CODEC_READER_MASK_RIGHT PIN1_bm
71 #define CODEC_READER_MASK (CODEC_READER_MASK_LEFT | CODEC_READER_MASK_RIGHT)
72 #define CODEC_READER_PINCTRL_LEFT PIN0CTRL
73 #define CODEC_READER_PINCTRL_RIGHT PIN1CTRL
74 #define CODEC_AC_DEMOD_SETTINGS AC_HSMODE_bm | AC_HYSMODE_NO_gc
75 #define CODEC_MAXIMUM_THRESHOLD 0xFFF // the maximum voltage can be calculated with ch0data * Vref / 0xFFF
76 #define CODEC_THRESHOLD_CALIBRATE_MIN 128
77 #define CODEC_THRESHOLD_CALIBRATE_MAX 1024
78 #define CODEC_THRESHOLD_CALIBRATE_STEPS 8
79 #define CODEC_TIMER_TIMESTAMPS TCD1
80 #define CODEC_TIMER_TIMESTAMPS_CCA_VECT TCD1_CCA_vect
81 
82 #define CODEC_BUFFER_SIZE 256
83 
84 #define CODEC_CARRIER_FREQ 13560000
85 
86 #define Codec8Reg0 GPIOR0
87 #define Codec8Reg1 GPIOR1
88 #define Codec8Reg2 GPIOR2
89 #define Codec8Reg3 GPIOR3
90 #define CodecCount16Register1 (*((volatile uint16_t*) &GPIOR4)) /* GPIOR4 & GPIOR5 */
91 #define CodecCount16Register2 (*((volatile uint16_t*) &GPIOR6)) /* GPIOR4 & GPIOR5 */
92 #define CodecPtrRegister1 (*((volatile uint8_t**) &GPIOR8))
93 #define CodecPtrRegister2 (*((volatile uint8_t**) &GPIORA))
94 
95 extern uint16_t ReaderThreshold;
96 extern uint16_t Reader_FWT;
97 
98 #define FWI2FWT(x) ((uint32_t)(256 * 16 * ((uint32_t)1 << (x))) / (CODEC_CARRIER_FREQ / 1000) + 1)
99 
100 typedef enum {
101  CODEC_SUBCARRIERMOD_OFF,
102  CODEC_SUBCARRIERMOD_OOK
103 } SubcarrierModType;
104 
105 extern uint8_t CodecBuffer[CODEC_BUFFER_SIZE];
106 
107 INLINE void CodecInit(void) {
108  ActiveConfiguration.CodecInitFunc();
109 }
110 
111 INLINE void CodecDeInit(void) {
112  ActiveConfiguration.CodecDeInitFunc();
113 }
114 
115 INLINE void CodecTask(void) {
116  ActiveConfiguration.CodecTaskFunc();
117 }
118 
119 /* Helper Functions for Codec implementations */
120 INLINE void CodecInitCommon(void)
121 {
122  /* Configure CARRIER input pin and route it to EVSYS.
123  * Multiply by 2 again by using both edges when externally
124  * dividing by 2 */
125 #if CODEC_CARRIER_IN_DIV == 2
126  CODEC_CARRIER_IN_PORT.CODEC_CARRIER_IN_PINCTRL = PORT_ISC_BOTHEDGES_gc;
127 #else
128 #error Option not supported
129 #endif
130  CODEC_CARRIER_IN_PORT.DIRCLR = CODEC_CARRIER_IN_MASK;
131  EVSYS.CH6MUX = CODEC_CARRIER_IN_EVMUX;
132 
133  /* Configure two DEMOD pins for input.
134  * Configure event channel 0 for rising edge (begin of modulation pause)
135  * Configure event channel 1 for falling edge (end of modulation pause) */
136  CODEC_DEMOD_POWER_PORT.OUTCLR = CODEC_DEMOD_POWER_MASK;
137  CODEC_DEMOD_POWER_PORT.DIRSET = CODEC_DEMOD_POWER_MASK;
138  CODEC_DEMOD_IN_PORT.DIRCLR = CODEC_DEMOD_IN_MASK;
139  CODEC_DEMOD_IN_PORT.CODEC_DEMOD_IN_PINCTRL0 = PORT_ISC_RISING_gc;
140  CODEC_DEMOD_IN_PORT.CODEC_DEMOD_IN_PINCTRL1 = PORT_ISC_FALLING_gc;
141  CODEC_DEMOD_IN_PORT.INT0MASK = 0;
142  CODEC_DEMOD_IN_PORT.INTCTRL = PORT_INT0LVL_HI_gc;
143  EVSYS.CH0MUX = CODEC_DEMOD_IN_EVMUX0;
144  EVSYS.CH1MUX = CODEC_DEMOD_IN_EVMUX1;
145 
146  /* Configure loadmod pin configuration and use a virtual port configuration
147  * for single instruction cycle access */
148  CODEC_LOADMOD_PORT.DIRSET = CODEC_LOADMOD_MASK;
149  CODEC_LOADMOD_PORT.OUTCLR = CODEC_LOADMOD_MASK;
150  PORTCFG.VPCTRLA &= ~PORTCFG_VP0MAP_gm;
151  PORTCFG.VPCTRLA |= PORTCFG_VP02MAP_PORTC_gc;
152 
153  /* Configure subcarrier pins for output */
154  CODEC_SUBCARRIER_PORT.DIRSET = CODEC_SUBCARRIER_MASK;
155  CODEC_SUBCARRIER_PORT.OUTCLR = CODEC_SUBCARRIER_MASK;
156 
157  /* Configure pins for reader field with the LEFT output being inverted
158  * and all bridge outputs static high */
159  CODEC_READER_PORT.CODEC_READER_PINCTRL_LEFT = PORT_INVEN_bm;
160  CODEC_READER_PORT.OUTCLR = CODEC_READER_MASK_LEFT;
161  CODEC_READER_PORT.OUTSET = CODEC_READER_MASK_RIGHT;
162  CODEC_READER_PORT.DIRSET = CODEC_READER_MASK;
163 
164  /* Configure timer for generating reader field and configure AWEX for outputting pattern
165  * with disabled outputs. */
166  CODEC_READER_TIMER.CTRLB = TC0_CCAEN_bm | TC_WGMODE_SINGLESLOPE_gc;
167  CODEC_READER_TIMER.PER = F_CPU / CODEC_CARRIER_FREQ - 1;
168  CODEC_READER_TIMER.CCA = F_CPU / CODEC_CARRIER_FREQ / 2 ;
169 
170  AWEXC.OUTOVEN = 0x00;
171  AWEXC.CTRL = AWEX_CWCM_bm | AWEX_DTICCAEN_bm | AWEX_DTICCBEN_bm;
172 
173  /* Configure DAC for the reference voltage */
174  DACB.EVCTRL = 0;
175  DACB.CTRLB = DAC_CHSEL_SINGLE_gc;
176  DACB.CTRLC = DAC_REFSEL_AVCC_gc;
177  DACB.CTRLA = DAC_IDOEN_bm | DAC_ENABLE_bm;
178  DACB.CH0DATA = ReaderThreshold; // real threshold voltage can be calculated with ch0data * Vref / 0xFFF
179 
180  /* Configure Analog Comparator 0 to detect changes in demodulated reader field */
181  ACA.AC0MUXCTRL = AC_MUXPOS_DAC_gc | AC_MUXNEG_PIN7_gc;
182  ACA.AC0CTRL = CODEC_AC_DEMOD_SETTINGS;
183 
184  /* Configure Analog Comparator 1 to detect SOC */
185  ACA.AC1MUXCTRL = AC_MUXPOS_DAC_gc | AC_MUXNEG_PIN7_gc;
186  ACA.AC1CTRL = CODEC_AC_DEMOD_SETTINGS;
187 }
188 
189 INLINE void CodecSetSubcarrier(SubcarrierModType ModType, uint16_t Divider)
190 {
191  if (ModType == CODEC_SUBCARRIERMOD_OFF) {
192  CODEC_SUBCARRIER_TIMER.CTRLA = TC_CLKSEL_OFF_gc;
193  CODEC_SUBCARRIER_TIMER.CTRLB = 0;
194  } else if (ModType == CODEC_SUBCARRIERMOD_OOK) {
195  /* Configure subcarrier generation with 50% DC output using OOK */
196  CODEC_SUBCARRIER_TIMER.CNT = 0;
197  CODEC_SUBCARRIER_TIMER.PER = Divider - 1;
198  CODEC_SUBCARRIER_TIMER.CODEC_SUBCARRIER_CC_OOK = Divider/2;
199  CODEC_SUBCARRIER_TIMER.CTRLB = CODEC_SUBCARRIER_CCEN_OOK | TC_WGMODE_SINGLESLOPE_gc;
200  }
201 }
202 
203 INLINE void CodecStartSubcarrier(void)
204 {
205  CODEC_SUBCARRIER_TIMER.CTRLA = CODEC_TIMER_CARRIER_CLKSEL;
206 }
207 
208 INLINE void CodecSetDemodPower(bool bOnOff)
209 {
210  if (bOnOff) {
211  CODEC_DEMOD_POWER_PORT.OUTSET = CODEC_DEMOD_POWER_MASK;
212  } else {
213  CODEC_DEMOD_POWER_PORT.OUTCLR = CODEC_DEMOD_POWER_MASK;
214  }
215 }
216 
217 INLINE bool CodecGetLoadmodState(void) {
218  if (ACA.STATUS & AC_AC0STATE_bm) {
219  return true;
220  } else {
221  return false;
222  }
223 }
224 
225 INLINE void CodecSetLoadmodState(bool bOnOff) {
226  if (bOnOff) {
227  VPORT0.OUT |= CODEC_LOADMOD_MASK;
228  } else {
229  VPORT0.OUT &= ~CODEC_LOADMOD_MASK;
230  }
231 }
232 
233 INLINE void CodecSetReaderField(bool bOnOff) { // this is the function for turning on/off the reader field dumbly; before using this function, please consider to use CodecReaderField{Start,Stop}
234 
235  if (bOnOff) {
236  /* Start timer for field generation and unmask outputs */
237  CODEC_READER_TIMER.CTRLA = TC_CLKSEL_DIV1_gc;
238  AWEXC.OUTOVEN = CODEC_READER_MASK;
239  } else {
240  /* Disable outputs of AWEX and stop field generation */
241  AWEXC.OUTOVEN = 0x00;
242  CODEC_READER_TIMER.CTRLA = TC_CLKSEL_OFF_gc;
243  }
244 }
245 
246 INLINE bool CodecGetReaderField(void) {
247  return (CODEC_READER_TIMER.CTRLA == TC_CLKSEL_DIV1_gc) && (AWEXC.OUTOVEN == CODEC_READER_MASK);
248 }
249 
250 void CodecReaderFieldStart(void);
251 void CodecReaderFieldStop(void);
252 bool CodecIsReaderFieldReady(void);
253 
254 void CodecReaderFieldRestart(uint16_t delay);
255 #define FIELD_RESTART() CodecReaderFieldRestart(100)
256 bool CodecIsReaderToBeRestarted(void);
257 
258 void CodecThresholdSet(uint16_t th);
259 uint16_t CodecThresholdIncrement(void);
260 void CodecThresholdReset(void);
261 #endif /* CODEC_H_ */
void(* CodecInitFunc)(void)
Definition: Configuration.h:59
void(* CodecTaskFunc)(void)
Definition: Configuration.h:65
void(* CodecDeInitFunc)(void)
Definition: Configuration.h:61