/* * CODEC.h * * Created on: 18.02.2013 * Author: skuser */ #ifndef CODEC_H_ #define CODEC_H_ #include #include #include #include "../Common.h" #include "../Configuration.h" #include "ISO14443-2A.h" #include "Reader14443-2A.h" /* Timing definitions for ISO14443A */ #define ISO14443A_SUBCARRIER_DIVIDER 16 #define ISO14443A_BIT_GRID_CYCLES 128 #define ISO14443A_BIT_RATE_CYCLES 128 #define ISO14443A_FRAME_DELAY_PREV1 1236 #define ISO14443A_FRAME_DELAY_PREV0 1172 #define ISO14443A_RX_PENDING_TIMEOUT 1 // ms /* Peripheral definitions */ #define CODEC_DEMOD_POWER_PORT PORTB #define CODEC_DEMOD_POWER_MASK PIN0_bm #define CODEC_DEMOD_IN_PORT PORTB #define CODEC_DEMOD_IN_MASK (CODEC_DEMOD_IN_MASK0 | CODEC_DEMOD_IN_MASK1) #define CODEC_DEMOD_IN_MASK0 PIN1_bm #define CODEC_DEMOD_IN_MASK1 PIN2_bm #define CODEC_DEMOD_IN_PINCTRL0 PIN1CTRL #define CODEC_DEMOD_IN_PINCTRL1 PIN2CTRL #define CODEC_DEMOD_IN_EVMUX0 EVSYS_CHMUX_PORTB_PIN1_gc #define CODEC_DEMOD_IN_EVMUX1 EVSYS_CHMUX_PORTB_PIN2_gc #define CODEC_DEMOD_IN_INT0_VECT PORTB_INT0_vect #define CODEC_LOADMOD_PORT PORTC #define CODEC_LOADMOD_MASK PIN6_bm #define CODEC_CARRIER_IN_PORT PORTC #define CODEC_CARRIER_IN_MASK PIN2_bm #define CODEC_CARRIER_IN_PINCTRL PIN2CTRL #define CODEC_CARRIER_IN_EVMUX EVSYS_CHMUX_PORTC_PIN2_gc #define CODEC_CARRIER_IN_DIV 2 /* external clock division factor */ #define CODEC_SUBCARRIER_PORT PORTC #define CODEC_SUBCARRIER_MASK_PSK PIN4_bm #define CODEC_SUBCARRIER_MASK_OOK PIN5_bm #define CODEC_SUBCARRIER_MASK (CODEC_SUBCARRIER_MASK_PSK | CODEC_SUBCARRIER_MASK_OOK) #define CODEC_SUBCARRIER_TIMER TCC1 #define CODEC_SUBCARRIER_CC_PSK CCA #define CODEC_SUBCARRIER_CC_OOK CCB #define CODEC_SUBCARRIER_CCEN_PSK TC1_CCAEN_bm #define CODEC_SUBCARRIER_CCEN_OOK TC1_CCBEN_bm #define CODEC_TIMER_SAMPLING TCD0 #define CODEC_TIMER_SAMPLING_CCA_VECT TCD0_CCA_vect #define CODEC_TIMER_SAMPLING_CCB_VECT TCD0_CCB_vect #define CODEC_TIMER_LOADMOD TCE0 #define CODEC_TIMER_LOADMOD_OVF_VECT TCE0_OVF_vect #define CODEC_TIMER_LOADMOD_CCA_VECT TCE0_CCA_vect #define CODEC_TIMER_LOADMOD_CCB_VECT TCE0_CCB_vect #define CODEC_TIMER_LOADMOD_CCC_VECT TCE0_CCC_vect #define CODEC_TIMER_MODSTART_EVSEL TC_EVSEL_CH0_gc #define CODEC_TIMER_MODEND_EVSEL TC_EVSEL_CH1_gc #define CODEC_TIMER_CARRIER_CLKSEL TC_CLKSEL_EVCH6_gc #define CODEC_READER_TIMER TCC0 #define CODEC_READER_PORT PORTC #define CODEC_READER_MASK_LEFT PIN0_bm #define CODEC_READER_MASK_RIGHT PIN1_bm #define CODEC_READER_MASK (CODEC_READER_MASK_LEFT | CODEC_READER_MASK_RIGHT) #define CODEC_READER_PINCTRL_LEFT PIN0CTRL #define CODEC_READER_PINCTRL_RIGHT PIN1CTRL #define CODEC_AC_DEMOD_SETTINGS AC_HSMODE_bm | AC_HYSMODE_NO_gc #define CODEC_MAXIMUM_THRESHOLD 0xFFF // the maximum voltage can be calculated with ch0data * Vref / 0xFFF #define CODEC_TIMER_TIMESTAMPS TCD1 #define CODEC_TIMER_TIMESTAMPS_CCA_VECT TCD1_CCA_vect #define CODEC_BUFFER_SIZE 256 #define CODEC_CARRIER_FREQ 13560000 #define Codec8Reg0 GPIOR0 #define Codec8Reg1 GPIOR1 #define Codec8Reg2 GPIOR2 #define Codec8Reg3 GPIOR3 #define CodecCount16Register1 (*((volatile uint16_t*) &GPIOR4)) /* GPIOR4 & GPIOR5 */ #define CodecCount16Register2 (*((volatile uint16_t*) &GPIOR6)) /* GPIOR4 & GPIOR5 */ #define CodecPtrRegister1 (*((volatile uint8_t**) &GPIOR8)) #define CodecPtrRegister2 (*((volatile uint8_t**) &GPIORA)) extern uint16_t ReaderThreshold; typedef enum { CODEC_SUBCARRIERMOD_OFF, CODEC_SUBCARRIERMOD_OOK } SubcarrierModType; extern uint8_t CodecBuffer[CODEC_BUFFER_SIZE]; INLINE void CodecInit(void) { ActiveConfiguration.CodecInitFunc(); } INLINE void CodecDeInit(void) { ActiveConfiguration.CodecDeInitFunc(); } INLINE void CodecTask(void) { ActiveConfiguration.CodecTaskFunc(); } /* Helper Functions for Codec implementations */ INLINE void CodecInitCommon(void) { /* Configure CARRIER input pin and route it to EVSYS. * Multiply by 2 again by using both edges when externally * dividing by 2 */ #if CODEC_CARRIER_IN_DIV == 2 CODEC_CARRIER_IN_PORT.CODEC_CARRIER_IN_PINCTRL = PORT_ISC_BOTHEDGES_gc; #else #error Option not supported #endif CODEC_CARRIER_IN_PORT.DIRCLR = CODEC_CARRIER_IN_MASK; EVSYS.CH6MUX = CODEC_CARRIER_IN_EVMUX; /* Configure two DEMOD pins for input. * Configure event channel 0 for rising edge (begin of modulation pause) * Configure event channel 1 for falling edge (end of modulation pause) */ CODEC_DEMOD_POWER_PORT.OUTCLR = CODEC_DEMOD_POWER_MASK; CODEC_DEMOD_POWER_PORT.DIRSET = CODEC_DEMOD_POWER_MASK; CODEC_DEMOD_IN_PORT.DIRCLR = CODEC_DEMOD_IN_MASK; CODEC_DEMOD_IN_PORT.CODEC_DEMOD_IN_PINCTRL0 = PORT_ISC_RISING_gc; CODEC_DEMOD_IN_PORT.CODEC_DEMOD_IN_PINCTRL1 = PORT_ISC_FALLING_gc; CODEC_DEMOD_IN_PORT.INT0MASK = 0; CODEC_DEMOD_IN_PORT.INTCTRL = PORT_INT0LVL_HI_gc; EVSYS.CH0MUX = CODEC_DEMOD_IN_EVMUX0; EVSYS.CH1MUX = CODEC_DEMOD_IN_EVMUX1; /* Configure loadmod pin configuration and use a virtual port configuration * for single instruction cycle access */ CODEC_LOADMOD_PORT.DIRSET = CODEC_LOADMOD_MASK; CODEC_LOADMOD_PORT.OUTCLR = CODEC_LOADMOD_MASK; PORTCFG.VPCTRLA &= ~PORTCFG_VP0MAP_gm; PORTCFG.VPCTRLA |= PORTCFG_VP02MAP_PORTC_gc; /* Configure subcarrier pins for output */ CODEC_SUBCARRIER_PORT.DIRSET = CODEC_SUBCARRIER_MASK; CODEC_SUBCARRIER_PORT.OUTCLR = CODEC_SUBCARRIER_MASK; /* Configure pins for reader field with the LEFT output being inverted * and all bridge outputs static high */ CODEC_READER_PORT.CODEC_READER_PINCTRL_LEFT = PORT_INVEN_bm; CODEC_READER_PORT.OUTCLR = CODEC_READER_MASK_LEFT; CODEC_READER_PORT.OUTSET = CODEC_READER_MASK_RIGHT; CODEC_READER_PORT.DIRSET = CODEC_READER_MASK; /* Configure timer for generating reader field and configure AWEX for outputting pattern * with disabled outputs. */ CODEC_READER_TIMER.CTRLB = TC0_CCAEN_bm | TC_WGMODE_SINGLESLOPE_gc; CODEC_READER_TIMER.PER = F_CPU / CODEC_CARRIER_FREQ - 1; CODEC_READER_TIMER.CCA = F_CPU / CODEC_CARRIER_FREQ / 2 ; AWEXC.OUTOVEN = 0x00; AWEXC.CTRL = AWEX_CWCM_bm | AWEX_DTICCAEN_bm | AWEX_DTICCBEN_bm; /* Configure DAC for the reference voltage */ DACB.EVCTRL = 0; DACB.CTRLB = DAC_CHSEL_SINGLE_gc; DACB.CTRLC = DAC_REFSEL_AVCC_gc; DACB.CTRLA = DAC_IDOEN_bm | DAC_ENABLE_bm; DACB.CH0DATA = ReaderThreshold; // real threshold voltage can be calculated with ch0data * Vref / 0xFFF /* Configure Analog Comparator 0 to detect changes in demodulated reader field */ ACA.AC0MUXCTRL = AC_MUXPOS_DAC_gc | AC_MUXNEG_PIN7_gc; ACA.AC0CTRL = CODEC_AC_DEMOD_SETTINGS; /* Configure Analog Comparator 1 to detect SOC */ ACA.AC1MUXCTRL = AC_MUXPOS_DAC_gc | AC_MUXNEG_PIN7_gc; ACA.AC1CTRL = CODEC_AC_DEMOD_SETTINGS; } INLINE void CodecSetSubcarrier(SubcarrierModType ModType, uint16_t Divider) { if (ModType == CODEC_SUBCARRIERMOD_OFF) { CODEC_SUBCARRIER_TIMER.CTRLA = TC_CLKSEL_OFF_gc; CODEC_SUBCARRIER_TIMER.CTRLB = 0; } else if (ModType == CODEC_SUBCARRIERMOD_OOK) { /* Configure subcarrier generation with 50% DC output using OOK */ CODEC_SUBCARRIER_TIMER.CNT = 0; CODEC_SUBCARRIER_TIMER.PER = Divider - 1; CODEC_SUBCARRIER_TIMER.CODEC_SUBCARRIER_CC_OOK = Divider/2; CODEC_SUBCARRIER_TIMER.CTRLB = CODEC_SUBCARRIER_CCEN_OOK | TC_WGMODE_SINGLESLOPE_gc; } } INLINE void CodecStartSubcarrier(void) { CODEC_SUBCARRIER_TIMER.CTRLA = CODEC_TIMER_CARRIER_CLKSEL; } INLINE void CodecSetDemodPower(bool bOnOff) { if (bOnOff) { CODEC_DEMOD_POWER_PORT.OUTSET = CODEC_DEMOD_POWER_MASK; } else { CODEC_DEMOD_POWER_PORT.OUTCLR = CODEC_DEMOD_POWER_MASK; } } INLINE bool CodecGetLoadmodState(void) { if (ACA.STATUS & AC_AC0STATE_bm) { return true; } else { return false; } } INLINE void CodecSetLoadmodState(bool bOnOff) { if (bOnOff) { VPORT0.OUT |= CODEC_LOADMOD_MASK; } else { VPORT0.OUT &= ~CODEC_LOADMOD_MASK; } } 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} if (bOnOff) { /* Start timer for field generation and unmask outputs */ CODEC_READER_TIMER.CTRLA = TC_CLKSEL_DIV1_gc; AWEXC.OUTOVEN = CODEC_READER_MASK; } else { /* Disable outputs of AWEX and stop field generation */ AWEXC.OUTOVEN = 0x00; CODEC_READER_TIMER.CTRLA = TC_CLKSEL_OFF_gc; } } INLINE bool CodecGetReaderField(void) { return (CODEC_READER_TIMER.CTRLA == TC_CLKSEL_DIV1_gc) && (AWEXC.OUTOVEN == CODEC_READER_MASK); } void CodecReaderFieldStart(void); void CodecReaderFieldStop(void); bool CodecIsReaderFieldReady(void); #endif /* CODEC_H_ */