diff --git a/arch/arm/src/sama5/Kconfig b/arch/arm/src/sama5/Kconfig index 48067482f8..435a647385 100644 --- a/arch/arm/src/sama5/Kconfig +++ b/arch/arm/src/sama5/Kconfig @@ -3235,6 +3235,7 @@ config SAMA5_ADC_DMASAMPLES config SAMA5_ADC_AUTOCALIB bool "ADC auto-calibration" + depends on ARCH_CHIP_SAMA5D3 default n ---help--- Perform ADC auto-calibration during the ADC initialization sequence @@ -3251,11 +3252,12 @@ config SAMA5_ADC_ANARCH default n ---help--- This option allows you to select different gain, offset, and single - vs. differential modes for each channel. + vs. differential modes for each channel, depending on ARCH. if SAMA5_ADC_ANARCH menu "Channel gain" + depends on ARCH_CHIP_SAMA5D config SAMA5_ADC_GAIN0 int "Channel 0 gain" @@ -3392,6 +3394,7 @@ config SAMA5_ADC_GAIN11 endmenu # Channel gain menu "Channel offsets" + depends on ARCH_CHIP_SAMA5D3 config SAMA5_ADC_OFFSET0 bool "Channel 0 offset" @@ -3492,6 +3495,7 @@ config SAMA5_ADC_OFFSET11 endmenu # Channel offsets menu "Channel differential mode" + depends on ARCH_CHIP_SAMA5D2 || ARCH_CHIP_SAMA5D3 config SAMA5_ADC_DIFFMODE0 bool "Channel 0 differential mode" @@ -3585,25 +3589,28 @@ if !SAMA5_ADC_ANARCH config SAMA5_ADC_GAIN int "Analog gain" default 1 - depends on SAMA5_ADC_CHAN0 + depends on ARCH_CHIP_SAMA5D3 range 0 3 ---help--- Valid gain settings are {0, 1, 2, 3} which may be interpreted as either {1, 1, 2, 4} if the channels are configured for single ended mode or as {0.5, 1, 2, 2} if the channels are configured for - differential mode. + differential mode. Applies to all channels. config SAMA5_ADC_OFFSET bool "Offset" default n + depends on ARCH_CHIP_SAMA5D3 ---help--- - Center the analog signal on Vrefin/2 before the gain scaling. + Center the analog signal on Vrefin/2 before the gain scaling for + all channels. + config SAMA5_ADC_DIFFMODE bool "Differential mode" default n ---help--- - Selects differential (vs. single-ended mode) + Selects differential (vs. single-ended mode) for all channels. endif # !SAMA5_ADC_ANARCH @@ -3620,6 +3627,16 @@ config SAMA5_ADC_SWTRIG ---help--- A-to-D Conversion is initiated only by software via an ioctl() +config SAMA5_ADC_PERIODIC_TRIG + bool "Periodic trigger" + ---help--- + A-to-D Conversion is triggered periodically + +config SAMA5_ADC_CONTINUOUS_TRIG + bool "Continuous trigger" + ---help--- + A-to-D Conversion is continuous + config SAMA5_ADC_ADTRG bool "External trigger via the ADTRG pin" ---help--- @@ -3632,12 +3649,45 @@ config SAMA5_ADC_TIOATRIG A-to-D Conversion is initiated the A output from one of Timer/Counter 0 channels. +config SAMA5_ADC_PWMTRIG + bool "PWM Event trigger" + depends on SAMA5_PWM + ---help--- + A-to-D Conversion is initiated from the PWM event lines + +config SAMA5_ADC_RTCOUT + bool "RTC Out trigger" + depends on SAMA5_RTC + depends on ARCH_CHIP_SAMA5D2 + ---help--- + A-to-D Conversion is initiated from the RTC output + endchoice # Trigger mode +if SAMA5_ADC_PWMTRIG + +choice + prompt "PWM Event Line Selection" + default SAMA5_ADC_PWMTRIG_LINE0 + +config SAMA5_ADC_PWM_TRIG_LINE0 + bool "PWM event Line 0" + ---help--- + Trigger A-to-D conversion on PWM event line 0 + +config SAMA5_ADC_PWM_TRIG_LINE1 + bool "PWM event Line 1" + ---help--- + Trigger A-to-D conversion on PWM event line 1 + +endchoice # PWM Event Line Selection +endif # SAMA5_ADC_PWMTRIG + +if SAMA5_ADC_ADTRG || SAMA5_ADC_TIOATRIG || SAMA5_ADC_PWMTRIG || SAMA5_ADC_RTCOUT + choice prompt "ADTRG edge" default SAMA5_ADC_ADTRG_BOTH - depends on SAMA5_ADC_ADTRG config SAMA5_ADC_ADTRG_RISING bool "Rising edge" @@ -3655,6 +3705,7 @@ config SAMA5_ADC_ADTRG_BOTH Trigger A-to-D conversion on both edges of the ADTRG signal endchoice # ADTRG edge +endif # SAMA5_ADC_ADTRG if SAMA5_ADC_TIOATRIG @@ -3717,6 +3768,17 @@ config SAMA5_ADC_TIOA_BOTH endchoice # ADTRG edge endif # SAMA5_ADC_TIOATRIG + +if SAMA5_ADC_PERIODIC_TRIG + +config SAMA5_ADC_TRIGGER_PERIOD + int "ADC Periodic Trigger Rate, useconds" + default 50000 + ---help--- + This setting determines the periodic sample trigger rate in useconds. + +endif # SAMA5_ADC_TRIGGER_PERIOD + endmenu # ADC Trigger Selection endif # SAMA5_ADC_HAVE_CHAN @@ -3798,6 +3860,12 @@ config SAMA5_TSD_NPOLLWAITERS ---help--- Maximum number of threads that can be waiting on poll() +config SAMA5_TSD_AUTOCALIB + bool "TSD auto-calibration" + default y + ---help--- + Perform TSD auto-calibration during the TSD initialization sequence + endif # SAMA5_TSD endmenu # Touchscreen Configuration endif # SAMA5_ADC diff --git a/arch/arm/src/sama5/hardware/_sama5d2x_memorymap.h b/arch/arm/src/sama5/hardware/_sama5d2x_memorymap.h index 45d986adf1..022acc8904 100644 --- a/arch/arm/src/sama5/hardware/_sama5d2x_memorymap.h +++ b/arch/arm/src/sama5/hardware/_sama5d2x_memorymap.h @@ -505,7 +505,7 @@ #define SAM_AIC_VBASE (SAM_PERIPHC_VSECTION+SAM_AIC_OFFSET) #define SAM_TWI1_VBASE (SAM_PERIPHC_VSECTION+SAM_TWI1_OFFSET) #define SAM_UDPHS_VBASE (SAM_PERIPHC_VSECTION+SAM_UDPHS_OFFSET) -#define SAM_ADC_VBASE (SAM_PERIPHC_VSECTION+SAM_ADC_OFFSET) +#define SAM_TSADC_VBASE (SAM_PERIPHC_VSECTION+SAM_ADC_OFFSET) #define SAM_PIO_VBASE (SAM_PERIPHC_VSECTION+SAM_PIO_OFFSET) #define SAM_MATRIX32_VBASE (SAM_PERIPHC_VSECTION+SAM_MATRIX1_OFFSET) #define SAM_SECUMOD_VBASE (SAM_PERIPHC_VSECTION+SAM_SECUMOD_OFFSET) diff --git a/arch/arm/src/sama5/hardware/sam_adc.h b/arch/arm/src/sama5/hardware/sam_adc.h index fa48bef94c..531aec1cd2 100644 --- a/arch/arm/src/sama5/hardware/sam_adc.h +++ b/arch/arm/src/sama5/hardware/sam_adc.h @@ -36,7 +36,7 @@ /* General definitions ******************************************************/ -#if defined(ATSAMA5D3) +#if defined(ATSAMA5D3) || defined(ATSAMA5D2) # define SAM_ADC_NCHANNELS 12 /* 12 ADC Channels */ #elif defined(ATSAMA5D4) # define SAM_ADC_NCHANNELS 5 /* 5 ADC Channels */ @@ -67,9 +67,10 @@ #ifdef ATSAMA5D3 # define SAM_ADC_CGR_OFFSET 0x0048 /* Channel Gain Register */ -# define SAM_ADC_COR_OFFSET 0x004c /* Channel Offset Register */ #endif +#define SAM_ADC_COR_OFFSET 0x004c /* Channel Offset Register */ + #define SAM_ADC_CDR_OFFSET(n) (0x0050+((n)<<2)) #define SAM_ADC_CDR0_OFFSET 0x0050 /* Channel Data Register 0 */ #define SAM_ADC_CDR1_OFFSET 0x0054 /* Channel Data Register 1 */ @@ -77,7 +78,7 @@ #define SAM_ADC_CDR3_OFFSET 0x005c /* Channel Data Register 3 */ #define SAM_ADC_CDR4_OFFSET 0x0060 /* Channel Data Register 4 */ -#ifdef ATSAMA5D3 +#if defined(ATSAMA5D3) || defined(ATSAMA5D2) # define SAM_ADC_CDR5_OFFSET 0x0064 /* Channel Data Register 5 */ # define SAM_ADC_CDR6_OFFSET 0x0068 /* Channel Data Register 6 */ # define SAM_ADC_CDR7_OFFSET 0x006c /* Channel Data Register 7 */ @@ -119,6 +120,9 @@ #ifdef ATSAMA5D3 # define SAM_ADC_CGR (SAM_TSADC_VBASE+SAM_ADC_CGR_OFFSET) +#endif + +#if defined(ATSAMA5D3) || defined(ATSAMA5D2) # define SAM_ADC_COR (SAM_TSADC_VBASE+SAM_ADC_COR_OFFSET) #endif @@ -129,7 +133,7 @@ #define SAM_ADC_CDR3 (SAM_TSADC_VBASE+SAM_ADC_CDR3_OFFSET) #define SAM_ADC_CDR4 (SAM_TSADC_VBASE+SAM_ADC_CDR4_OFFSET) -#ifdef ATSAMA5D3 +#if defined(ATSAMA5D3) || defined(ATSAMA5D2) # define SAM_ADC_CDR5 (SAM_TSADC_VBASE+SAM_ADC_CDR5_OFFSET) # define SAM_ADC_CDR6 (SAM_TSADC_VBASE+SAM_ADC_CDR6_OFFSET) # define SAM_ADC_CDR7 (SAM_TSADC_VBASE+SAM_ADC_CDR7_OFFSET) @@ -170,6 +174,8 @@ # define ADC_MR_TRGSEL_TIOA2 (3 << ADC_MR_TRGSEL_SHIFT) /* TIOA2 */ # define ADC_MR_TRGSEL_PWM0 (4 << ADC_MR_TRGSEL_SHIFT) /* PWM Event Line 0 */ # define ADC_MR_TRGSEL_PWM1 (5 << ADC_MR_TRGSEL_SHIFT) /* PWM Event Line 1 */ +# define ADC_MR_TRGSEL_TIOA3 (6 << ADC_MR_TRGSEL_SHIFT) /* TIOA3 */ +# define ADC_MR_TRGSEL_RTC (7 << ADC_MR_TRGSEL_SHIFT) /* RTC Out */ #ifdef ATSAMA5D4 # define ADC_MR_LOWRES (1 << 4) /* Bit 4: LOWRES: Resolution */ @@ -186,13 +192,13 @@ # define ADC_MR_PRESCAL(n) ((uint32_t)(n) << ADC_MR_PRESCAL_SHIFT) #define ADC_MR_STARTUP_SHIFT (16) /* Bits 16-19: Start Up Time */ #define ADC_MR_STARTUP_MASK (15 << ADC_MR_STARTUP_SHIFT) -# define ADC_MR_STARTUP_0 (0 << ADC_MR_STARTUP_SHIFT) /* 0 periods of ADCClock */ -# define ADC_MR_STARTUP_8 (1 << ADC_MR_STARTUP_SHIFT) /* 8 periods of ADCClock */ -# define ADC_MR_STARTUP_16 (2 << ADC_MR_STARTUP_SHIFT) /* 16 periods of ADCClock */ -# define ADC_MR_STARTUP_24 (3 << ADC_MR_STARTUP_SHIFT) /* 24 periods of ADCClock */ -# define ADC_MR_STARTUP_64 (4 << ADC_MR_STARTUP_SHIFT) /* 64 periods of ADCClock */ -# define ADC_MR_STARTUP_80 (5 << ADC_MR_STARTUP_SHIFT) /* 80 periods of ADCClock */ -# define ADC_MR_STARTUP_96 (6 << ADC_MR_STARTUP_SHIFT) /* 96 periods of ADCClock */ +# define ADC_MR_STARTUP_0 (0 << ADC_MR_STARTUP_SHIFT) /* 0 periods of ADCClock */ +# define ADC_MR_STARTUP_8 (1 << ADC_MR_STARTUP_SHIFT) /* 8 periods of ADCClock */ +# define ADC_MR_STARTUP_16 (2 << ADC_MR_STARTUP_SHIFT) /* 16 periods of ADCClock */ +# define ADC_MR_STARTUP_24 (3 << ADC_MR_STARTUP_SHIFT) /* 24 periods of ADCClock */ +# define ADC_MR_STARTUP_64 (4 << ADC_MR_STARTUP_SHIFT) /* 64 periods of ADCClock */ +# define ADC_MR_STARTUP_80 (5 << ADC_MR_STARTUP_SHIFT) /* 80 periods of ADCClock */ +# define ADC_MR_STARTUP_96 (6 << ADC_MR_STARTUP_SHIFT) /* 96 periods of ADCClock */ # define ADC_MR_STARTUP_112 (7 << ADC_MR_STARTUP_SHIFT) /* 112 periods of ADCClock */ # define ADC_MR_STARTUP_512 (8 << ADC_MR_STARTUP_SHIFT) /* 512 periods of ADCClock */ # define ADC_MR_STARTUP_576 (9 << ADC_MR_STARTUP_SHIFT) /* 576 periods of ADCClock */ @@ -204,13 +210,22 @@ # define ADC_MR_STARTUP_960 (15 << ADC_MR_STARTUP_SHIFT) /* 960 periods of ADCClock */ #ifdef ATSAMA5D3 -# define ADC_MR_SETTLING_SHIFT (20) /* Bits 20-21: Analog Settling Time */ +# define ADC_MR_SETTLING_SHIFT (20) /* Bits 20-21: Analog Settling Time */ # define ADC_MR_SETTLING_MASK (15 << ADC_MR_SETTLING_SHIFT) -# define ADC_MR_SETTLING_3 (0 << ADC_MR_SETTLING_SHIFT) /* 3 periods of ADCClock */ -# define ADC_MR_SETTLING_5 (1 << ADC_MR_SETTLING_SHIFT) /* 5 periods of ADCClock */ -# define ADC_MR_SETTLING_9 (2 << ADC_MR_SETTLING_SHIFT) /* 9 periods of ADCClock */ -# define ADC_MR_SETTLING_17 (3 << ADC_MR_SETTLING_SHIFT) /* 17 periods of ADCClock */ +# define ADC_MR_SETTLING_3 (0 << ADC_MR_SETTLING_SHIFT) /* 3 periods of ADCClock */ +# define ADC_MR_SETTLING_5 (1 << ADC_MR_SETTLING_SHIFT) /* 5 periods of ADCClock */ +# define ADC_MR_SETTLING_9 (2 << ADC_MR_SETTLING_SHIFT) /* 9 periods of ADCClock */ +# define ADC_MR_SETTLING_17 (3 << ADC_MR_SETTLING_SHIFT) /* 17 periods of ADCClock */ +#else +# define ADC_MR_SETTLING_SHIFT (20) /* Not present in SAMA5D2 or SAMA5D4 */ +# define ADC_MR_SETTLING_MASK (0) +# define ADC_MR_SETTLING_3 (0 << ADC_MR_SETTLING_SHIFT) /* n/a periods of ADCClock */ +# define ADC_MR_SETTLING_5 (0 << ADC_MR_SETTLING_SHIFT) /* n/a periods of ADCClock */ +# define ADC_MR_SETTLING_9 (0 << ADC_MR_SETTLING_SHIFT) /* n/a periods of ADCClock */ +# define ADC_MR_SETTLING_17 (0 << ADC_MR_SETTLING_SHIFT) /* n/a periods of ADCClock */ +#endif +#if defined(ATSAMA5D3) || defined(ATSAMA5D2) # define ADC_MR_ANACH (1 << 23) /* Bit 23: Analog Change */ #endif @@ -218,7 +233,7 @@ #define ADC_MR_TRACKTIM_MASK (15 << ADC_MR_TRACKTIM_SHIFT) # define ADC_MR_TRACKTIM(n) ((uint32_t)(n) << ADC_MR_TRACKTIM_SHIFT) -#ifdef ATSAMA5D3 +#if defined(ATSAMA5D3) || defined(ATSAMA5D2) # define ADC_MR_TRANSFER_SHIFT (28) /* Bits 28-29: Transfer Period */ # define ADC_MR_TRANSFER_MASK (3 << ADC_MR_TRANSFER_SHIFT) # define ADC_MR_TRANSFER (2 << ADC_MR_TRANSFER_SHIFT) /* Must be 2 */ @@ -259,7 +274,7 @@ # define ADC_SEQR1_USCH8(v) ((uint32_t)(v) << ADC_SEQR1_USCH8_SHIFT) #endif -#ifdef ATSAMA5D3 +#if defined(ATSAMA5D3) || defined(ATSAMA5D2) /* Channel Sequence Register 2 */ # define ADC_SEQR2_USCH_SHIFT(n) (((n)-9) << 2) /* n=9..11 */ @@ -289,7 +304,7 @@ #define ADC_CH4 (1 << 4) /* Bit 4: Channel 4 Enable */ #define ADC_CH5 (1 << 5) /* Bit 5: Channel 5 Enable */ -#ifdef ATSAMA5D3 +#if defined(ATSAMA5D3) || defined(ATSAMA5D2) # define ADC_CH6 (1 << 6) /* Bit 6: Channel 6 Enable */ # define ADC_CH7 (1 << 7) /* Bit 7: Channel 7 Enable */ # define ADC_CH8 (1 << 8) /* Bit 8: Channel 8 Enable */ @@ -301,7 +316,7 @@ #define TSD_4WIRE_ALL (0x0000000f) #define TSD_5WIRE_ALL (0x0000001f) -#if defined(ATSAMA5D3) +#if defined(ATSAMA5D3) || defined(ATSAMA5D2) # define ADC_CHALL (0x00000fff) #elif defined(ATSAMA5D4) # define ADC_CHALL (0x0000001f) @@ -327,7 +342,7 @@ #define ADC_INT_EOC3 (1 << 3) /* Bit 3: End of Conversion 3 */ #define ADC_INT_EOC4 (1 << 4) /* Bit 4: End of Conversion 4 */ -#if defined(ATSAMA5D3) +#if defined(ATSAMA5D3) || defined(ATSAMA5D2) # define ADC_INT_EOC5 (1 << 5) /* Bit 5: End of Conversion 5 */ # define ADC_INT_EOC6 (1 << 6) /* Bit 6: End of Conversion 6 */ # define ADC_INT_EOC7 (1 << 7) /* Bit 7: End of Conversion 7 */ @@ -355,7 +370,11 @@ #define ADC_INT_NOPEN (1 << 30) /* Bit 30: No Pen Contact Interrupt */ #define ADC_SR_PENS (1 << 31) /* Bit 31: Pen detect Status (SR only) */ -#define ADC_INT_ALL (0xe7f00fff) +#if defined(ATSAMA5D3) +# define ADC_INT_ALL (0xe7f00fff) +#elif defined(ATSAMA5D2) +# define ADC_INT_ALL (0x67780fff) +#endif /* Overrun Status Register */ @@ -484,7 +503,12 @@ /* Channel Data Register */ #define ADC_CDR_DATA_SHIFT (0) /* Bits 0-11: Converted Data */ -#define ADC_CDR_DATA_MASK (0xfff << ADC_CDR_DATA_SHIFT) + +#if defined(ATSAMA5D2) +# define ADC_CDR_DATA_MASK (0x3fff << ADC_CDR_DATA_SHIFT) +#else +# define ADC_CDR_DATA_MASK (0xfff << ADC_CDR_DATA_SHIFT) +#endif /* Compare Window Register */ @@ -501,6 +525,12 @@ #define ADC_ACR_PENDETSENS_MASK (3 << ADC_ACR_PENDETSENS_SHIFT) # define ADC_ACR_PENDETSENS(n) ((uint32_t)(n) << ADC_ACR_PENDETSENS_SHIFT) +#if defined(ATSAMA5D2) +# define ADC_ACR_IBTL_SHIFT (8) /* Bits 8-9: ADC Bias Current Control */ +# define ADC_ACR_IBCTL_MASK (3 << ADC_ACR_IBTL_SHIFT) +# define ADC_ACR_IBCTL(n) ((uint32_t)(n) << ADC_ACR_IBTL_SHIFT) +#endif + /* Touchscreen Mode Register */ #define ADC_TSMR_TSMODE_SHIFT (0) /* Bit 0-1: Touchscreen Mode */ diff --git a/arch/arm/src/sama5/sam_adc.c b/arch/arm/src/sama5/sam_adc.c index 6399524627..846a71b9e7 100644 --- a/arch/arm/src/sama5/sam_adc.c +++ b/arch/arm/src/sama5/sam_adc.c @@ -475,6 +475,7 @@ static void sam_adc_gain(struct sam_adc_s *priv); static void sam_adc_analogchange(struct sam_adc_s *priv); static void sam_adc_sequencer(struct sam_adc_s *priv); static void sam_adc_channels(struct sam_adc_s *priv); +static void sam_adc_trigperiod(struct sam_adc_s *priv, uint32_t period); #endif /**************************************************************************** @@ -834,6 +835,75 @@ static int sam_adc_dmasetup(struct sam_adc_s *priv, uint8_t *buffer, } #endif +/**************************************************************************** + * Name: sam_tsd_trigperiod + * + * Description: + * Set the TGPER field of the TRGR register in order to define a periodic + * trigger perioc. + * + * Trigger Period = (TRGPER+1) / ADCCLK + * + * Input Parameters: + * priv - A reference to the touchscreen device structure + * time - The new trigger period in microseconds + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void sam_adc_trigperiod(struct sam_adc_s *priv, uint32_t period) +{ + uint32_t trigper; + uint32_t regval; + uint32_t div; + + /* Divide trigger period avoid overflows. Division by ten is awkard, but + * appropriate here because times are specified in decimal with lots of + * zeroes. + */ + + div = 100000; + while (period >= 10 && div >= 10) + { + period /= 10; + div /= 10; + } + + /* Calculate and adjust the scaled trigger period: + * + * Trigger Period = (TRGPER+1) / ADCCLK + */ + + trigper = (period * BOARD_ADCCLK_FREQUENCY) / div; + if ((trigper % 10) != 0) + { + /* Handle partial values by not decrementing trigper. This is + * basically a 'ceil' operation. + */ + + trigper /= 10; + } + else + { + /* The final value needs to be decrement by one */ + + trigper /= 10; + if (trigper > 0) + { + trigper--; + } + } + + /* Set the calculated trigger period in the TRGR register */ + + regval = sam_adc_getreg(priv, SAM_ADC_TRGR); + regval &= ~ADC_TRGR_TRGPER_MASK; + regval |= ADC_TRGR_TRGPER(trigper); + sam_adc_putreg(priv, SAM_ADC_TRGR, regval); +} + /**************************************************************************** * ADC interrupt handling ****************************************************************************/ @@ -865,7 +935,7 @@ static void sam_adc_endconversion(void *arg) int ret; DEBUGASSERT(priv != NULL); - ainfo("pending=%08x\n", priv->pending); + ainfo("pending=%08lx\n", priv->pending); /* Get the set of unmasked, pending ADC interrupts */ @@ -1027,9 +1097,7 @@ static int sam_adc_bind(struct adc_dev_s *dev, static void sam_adc_reset(struct adc_dev_s *dev) { -#ifdef CONFIG_SAMA5_ADC_DMA struct sam_adc_s *priv = (struct sam_adc_s *)dev->ad_priv; -#endif uint32_t regval; ainfo("Resetting..\n"); @@ -1069,10 +1137,13 @@ static void sam_adc_reset(struct adc_dev_s *dev) /* Reset gain, offset, differential modes */ +#if defined (ATSAMA5D3) sam_adc_putreg(priv, SAM_ADC_CGR, 0); + #endif + sam_adc_putreg(priv, SAM_ADC_COR, 0); -#ifndef CONFIG_SAMA5_ADC_SWTRIG +#if !defined CONFIG_SAMA5_ADC_SWTRIG && !defined CONFIG_SAMA5_TSD /* Select software trigger (i.e., basically no trigger) */ regval = sam_adc_getreg(priv, SAM_ADC_MR); @@ -1101,11 +1172,12 @@ static int sam_adc_setup(struct adc_dev_s *dev) { struct sam_adc_s *priv = (struct sam_adc_s *)dev->ad_priv; uint32_t regval; + int ret; ainfo("Setup\n"); /* Enable channel number tag. This bit will force the channel number - * (CHNB) to be included in the LDCR register content. + * (CHNB) to be included in the LDCR register content */ regval = sam_adc_getreg(priv, SAM_ADC_EMR); @@ -1121,7 +1193,7 @@ static int sam_adc_setup(struct adc_dev_s *dev) sam_adc_channels(priv); /* Enable/disable analog change. This feature permits different settings - * per channel. + * per channel */ sam_adc_analogchange(priv); @@ -1153,6 +1225,10 @@ static int sam_adc_setup(struct adc_dev_s *dev) #endif + /* Now we are initialized */ + + priv->initialized = true; + /* Configure trigger mode and start conversion */ return sam_adc_trigger(priv); @@ -1179,6 +1255,11 @@ static void sam_adc_shutdown(struct adc_dev_s *dev) sam_adc_reset(dev); +#ifndef CONFIG_SAMA5_TSD + /* doing this if the TSD is required will stop it working */ + + /* Needs revisit */ + /* Disable ADC interrupts at the level of the AIC */ up_disable_irq(SAM_IRQ_ADC); @@ -1186,6 +1267,7 @@ static void sam_adc_shutdown(struct adc_dev_s *dev) /* Then detach the ADC interrupt handler. */ irq_detach(SAM_IRQ_ADC); +#endif } /**************************************************************************** @@ -1335,7 +1417,7 @@ static int sam_adc_settimer(struct sam_adc_s *priv, uint32_t frequency, priv->tc = sam_tc_allocate(channel, mode); if (!priv->tc) { - aerr("ERROR: Failed to allocate channel %d mode %08" PRIx32 "\n", + aerr("ERROR: Failed to allocate channel %d mode %08x\n", channel, mode); return -EINVAL; } @@ -1413,17 +1495,33 @@ static int sam_adc_trigger(struct sam_adc_s *priv) /* Configure the software trigger */ - regval = sam_adc_getreg(priv, SAM_ADC_MR); - regval &= ~ADC_MR_TRGSEL_MASK; - sam_adc_putreg(priv, SAM_ADC_MR, regval); - - /* No trigger, only software trigger can start conversions */ - regval = sam_adc_getreg(priv, SAM_ADC_TRGR); regval &= ~ADC_TRGR_TRGMOD_MASK; regval |= ADC_TRGR_TRGMOD_NOTRIG; sam_adc_putreg(priv, SAM_ADC_TRGR, regval); +#elif defined(CONFIG_SAMA5_ADC_PERIODIC_TRIG) + ainfo("Setup Periodic Trigger\n"); + + /* Configure the trigger to be periodic */ + + sam_adc_trigperiod(priv, CONFIG_SAMA5_ADC_TRIGGER_PERIOD); + + regval = sam_adc_getreg(priv, SAM_ADC_TRGR); + regval &= ~ADC_TRGR_TRGMOD_MASK; + regval |= ADC_TRGR_TRGMOD_PERIOD; + sam_adc_putreg(priv, SAM_ADC_TRGR, regval); + +#elif defined(CONFIG_SAMA5_ADC_CONTINUOUS_TRIG) + ainfo("Setup Continuous Trigger\n"); + + /* Configure the trigger to be continuous */ + + regval = sam_adc_getreg(priv, SAM_ADC_TRGR); + regval &= ~ADC_TRGR_TRGMOD_MASK; + regval |= ADC_TRGR_TRGMOD_CONT; + sam_adc_putreg(priv, SAM_ADC_TRGR, regval); + #elif defined(CONFIG_SAMA5_ADC_ADTRG) ainfo("Setup ADTRG trigger\n"); @@ -1431,7 +1529,70 @@ static int sam_adc_trigger(struct sam_adc_s *priv) regval = sam_adc_getreg(priv, SAM_ADC_MR); regval &= ~ADC_MR_TRGSEL_MASK; - regval |= ADC_MR_TRGSEL_ADC_ADTRIG; + regval |= ADC_MR_TRGSEL_ADTRG; + sam_adc_putreg(priv, SAM_ADC_MR, regval); + + /* External trigger edge selection */ + + regval = sam_adc_getreg(priv, SAM_ADC_TRGR); + regval &= ~ADC_TRGR_TRGMOD_MASK; + +#if defined(CONFIG_SAMA5_ADC_ADTRG_RISING) + regval |= ADC_TRGR_TRGMOD_EXTRISE; +#elif defined(CONFIG_SAMA5_ADC_ADTRG_FALLING) + regval |= ADC_TRGR_TRGMOD_EXTFALL; +#elif defined(CONFIG_SAMA5_ADC_ADTRG_BOTH) + regval |= ADC_TRGR_TRGMOD_EXTBOTH; +#else +# error External trigger edge not defined +#endif + + sam_adc_putreg(priv, SAM_ADC_TRGR, regval); + +#elif defined(CONFIG_SAMA5_ADC_PWMTRIG) + ainfo("Setup PWM trigger\n"); + + /* Configure the trigger via the PWM event lines */ + + regval = sam_adc_getreg(priv, SAM_ADC_MR); + regval &= ~ADC_MR_TRGSEL_MASK; + +#if defined(CONFIG_SAMA5_ADC_PWM_TRIG_LINE0) + regval |= ADC_MR_TRGSEL_PWM0; +#elif defined(CONFIG_SAMA5_ADC_PWM_TRIG_LINE1) + regval |= ADC_MR_TRGSEL_PWM1; +#else +# error PWM event line not defined +#endif + + sam_adc_putreg(priv, SAM_ADC_MR, regval); + + /* External trigger edge selection */ + + regval = sam_adc_getreg(priv, SAM_ADC_TRGR); + regval &= ~ADC_TRGR_TRGMOD_MASK; + +#if defined(CONFIG_SAMA5_ADC_ADTRG_RISING) + regval |= ADC_TRGR_TRGMOD_EXTRISE; +#elif defined(CONFIG_SAMA5_ADC_ADTRG_FALLING) + regval |= ADC_TRGR_TRGMOD_EXTFALL; +#elif defined(CONFIG_SAMA5_ADC_ADTRG_BOTH) + regval |= ADC_TRGR_TRGMOD_EXTBOTH; +#else +# error External trigger edge not defined +#endif + + sam_adc_putreg(priv, SAM_ADC_TRGR, regval); + +#elif defined(CONFIG_SAMA5_ADC_RTCOUT) + ainfo("Setup RTC trigger\n"); + + /* Configure the trigger via the PWM event lines */ + + regval = sam_adc_getreg(priv, SAM_ADC_MR); + regval &= ~ADC_MR_TRGSEL_MASK; + regval |= ADC_MR_TRGSEL_RTC; + sam_adc_putreg(priv, SAM_ADC_MR, regval); /* External trigger edge selection */ @@ -1674,7 +1835,8 @@ static void sam_adc_offset(struct sam_adc_s *priv) static void sam_adc_gain(struct sam_adc_s *priv) { -#ifdef CONFIG_SAMA5_ADC_ANARCH +#ifdef ATSAMA5D3 +# ifdef CONFIG_SAMA5_ADC_ANARCH uint32_t regval; ainfo("Entry\n"); @@ -1728,7 +1890,8 @@ static void sam_adc_gain(struct sam_adc_s *priv) /* Set GAIN0 only. GAIN0 will be used for all channels. */ sam_adc_putreg(priv, SAM_ADC_CGR, ADC_CGR_GAIN0(CONFIG_SAMA5_ADC_GAIN)); -#endif +#endif /* CONFIG_SAMA5_ADC_ANARCH */ +#endif /* ATSAMA5D3 */ } /**************************************************************************** @@ -2050,9 +2213,17 @@ struct adc_dev_s *sam_adc_initialize(void) /* Initialize the public ADC device data structure */ #ifdef SAMA5_ADC_HAVE_CHANNELS + g_adcdev.ad_ops = &g_adcops; priv->dev = &g_adcdev; #endif + g_adcdev.ad_priv = priv; + + /* Initialize the private ADC device data structure */ + + nxmutex_init(&priv->lock); + priv->cb = NULL; + #ifdef CONFIG_SAMA5_ADC_DMA /* Allocate a DMA channel from DMAC1 */ @@ -2132,6 +2303,9 @@ struct adc_dev_s *sam_adc_initialize(void) ADC_MR_SETTLING_MASK); regval |= (ADC_MR_STARTUP_512 | ADC_MR_TRACKTIM(0) | ADC_MR_SETTLING_17); +#if defined ATSAMA5D2 + regval |= ADC_MR_TRANSFER; +#endif sam_adc_putreg(priv, SAM_ADC_MR, regval); /* Attach the ADC interrupt */ diff --git a/arch/arm/src/sama5/sam_tsd.c b/arch/arm/src/sama5/sam_tsd.c index 800a414bae..959425cc47 100644 --- a/arch/arm/src/sama5/sam_tsd.c +++ b/arch/arm/src/sama5/sam_tsd.c @@ -137,6 +137,18 @@ # define MAX(a,b) (((a) > (b)) ? (a) : (b)) #endif +#ifndef BOARD_TSSCTIM +# define BOARD_TSSCTIM 0 +#endif + +#ifndef BOARD_TSD_PENDETSENS +# define BOARD_TSD_PENDETSENS 0 +#endif + +#if !defined BOARD_TSD_IBCTL && defined ATSAMA5D2 +# define BOARD_TSD_IBCTL 0 +#endif + /**************************************************************************** * Private Types ****************************************************************************/ @@ -449,6 +461,7 @@ static void sam_tsd_setaverage(struct sam_tsd_s *priv, uint32_t tsav) */ minfreq = (tsav >> ADC_TSMR_TSAV_SHIFT); + if (minfreq) { /* TSFREQ: Defines the Touchscreen Frequency compared to the Trigger @@ -460,9 +473,11 @@ static void sam_tsd_setaverage(struct sam_tsd_s *priv, uint32_t tsav) { /* Set TSFREQ = TSAV */ - regval &= ~ADC_TSMR_TSFREQ_MASK; - regval |= ADC_TSMR_TSFREQ(minfreq); + tsfreq = minfreq; } + + regval &= ~ADC_TSMR_TSFREQ_MASK; + regval |= ADC_TSMR_TSFREQ(minfreq); } /* Save the new filter value */ @@ -565,10 +580,12 @@ static void sam_tsd_bottomhalf(void *arg) sam_tsd_setaverage(priv, ADC_TSMR_TSAV_NOFILTER); sam_tsd_debounce(priv, BOARD_TSD_DEBOUNCE); +#ifdef SAMA5_TSD_PENDET_TRIG_ALLOWED regval = sam_adc_getreg(priv->adc, SAM_ADC_TRGR); regval &= ~ADC_TRGR_TRGMOD_MASK; regval |= ADC_TRGR_TRGMOD_PEN; sam_adc_putreg(priv->adc, SAM_ADC_TRGR, regval); +#endif } /* It is a pen down event. If the last loss-of-contact event has not been @@ -609,6 +626,39 @@ static void sam_tsd_bottomhalf(void *arg) /* But don't enable interrupts for the data that we already have */ ier &= ~(pending & TSD_ALLREADY); + + /* datasheet suggests that if TSAV != 0 there may not be interrupts + * for TSD channels so periodic or continuous triggers are needed + * + * Testing suggests otherwise, so periodic is used regardless. + */ +#if 0 + regval = sam_adc_getreg(priv->adc, SAM_ADC_TSMR); + regval &= ADC_TSMR_TSAV_MASK; + if ((regval & ADC_TSMR_TSAV_MASK) != 0) +#endif +#ifdef SAMA5_TSD_PENDET_TRIG_ALLOWED + { + regval = sam_adc_getreg(priv->adc, SAM_ADC_TRGR); + + if ((regval & ADC_TRGR_TRGMOD_MASK) == ADC_TRGR_TRGMOD_PEN) + { + /* Configure for periodic trigger */ + + regval &= ~ADC_TRGR_TRGMOD_MASK; + regval |= ADC_TRGR_TRGMOD_PERIOD; + sam_adc_putreg(priv->adc, SAM_ADC_TRGR, regval); + } + else + { + regval = sam_adc_getreg(priv->adc, SAM_ADC_TRGR); + regval &= ~ADC_TRGR_TRGMOD_MASK; + regval |= ADC_TRGR_TRGMOD_PEN; + sam_adc_putreg(priv->adc, SAM_ADC_TRGR, regval); + } + } +#endif + goto ignored; } @@ -704,14 +754,25 @@ static void sam_tsd_bottomhalf(void *arg) * resistance (Rxp). Three conversions (Xpos, Z1, Z2) are * necessary to determine the value of Rp (Zaxis resistance). * - * Rp = Rxp * (Xraw / 1024) * [(Z2 / Z1) - 1] + * Rp = Rxp * (X / 1024) * [(Z2 / Z1) - 1] + * + * Revisited. The ADC is 12 bit not 10 so datasheet is presumed + * incorrect. Formula corrected to cope with uint arithmetic. */ z2 = (pressr & ADC_PRESSR_Z2_MASK) >> ADC_PRESSR_Z2_SHIFT; z1 = (pressr & ADC_PRESSR_Z1_MASK) >> ADC_PRESSR_Z1_SHIFT; - p = CONFIG_SAMA_TSD_RXP * xraw * (z2 - z1) / z1; - priv->sample.p = MIN(p, UINT16_MAX); + if (z1 != 0) + { + p = CONFIG_SAMA_TSD_RXP * xraw * (z2 - z1) / (z1 * 4096); + } + else + { + p = 4096; + } + + priv->sample.p = MIN(p, 4096); #endif /* The X/Y positional data is now valid */ @@ -730,6 +791,7 @@ static void sam_tsd_bottomhalf(void *arg) priv->sample.contact = CONTACT_DOWN; +#ifdef SAMA5_TSD_PENDET_TRIG_ALLOWED /* Configure for periodic trigger */ sam_tsd_setaverage(priv, ADC_TSMR_TSAV_8CONV); @@ -739,6 +801,7 @@ static void sam_tsd_bottomhalf(void *arg) regval &= ~ADC_TRGR_TRGMOD_MASK; regval |= ADC_TRGR_TRGMOD_PERIOD; sam_adc_putreg(priv->adc, SAM_ADC_TRGR, regval); +#endif } } @@ -833,7 +896,6 @@ static int sam_tsd_open(struct file *filep) /* Get exclusive access to the device structures */ sam_adc_lock(priv->adc); - /* Increment the count of references to the device. If this the first * time that the driver has been opened for this device, then initialize * the device. @@ -1202,67 +1264,67 @@ static void sam_tsd_startuptime(struct sam_tsd_s *priv, uint32_t time) if (startup > 896) { - regval = ADC_MR_STARTUP_960; + regval |= ADC_MR_STARTUP_960; } else if (startup > 832) { - regval = ADC_MR_STARTUP_896; + regval |= ADC_MR_STARTUP_896; } else if (startup > 768) { - regval = ADC_MR_STARTUP_832; + regval |= ADC_MR_STARTUP_832; } else if (startup > 704) { - regval = ADC_MR_STARTUP_768; + regval |= ADC_MR_STARTUP_768; } else if (startup > 640) { - regval = ADC_MR_STARTUP_704; + regval |= ADC_MR_STARTUP_704; } else if (startup > 576) { - regval = ADC_MR_STARTUP_640; + regval |= ADC_MR_STARTUP_640; } else if (startup > 512) { - regval = ADC_MR_STARTUP_576; + regval |= ADC_MR_STARTUP_576; } else if (startup > 112) { - regval = ADC_MR_STARTUP_512; + regval |= ADC_MR_STARTUP_512; } else if (startup > 96) { - regval = ADC_MR_STARTUP_112; + regval |= ADC_MR_STARTUP_112; } else if (startup > 80) { - regval = ADC_MR_STARTUP_96; + regval |= ADC_MR_STARTUP_96; } else if (startup > 64) { - regval = ADC_MR_STARTUP_80; + regval |= ADC_MR_STARTUP_80; } else if (startup > 24) { - regval = ADC_MR_STARTUP_64; + regval |= ADC_MR_STARTUP_64; } else if (startup > 16) { - regval = ADC_MR_STARTUP_24; + regval |= ADC_MR_STARTUP_24; } else if (startup > 8) { - regval = ADC_MR_STARTUP_16; + regval |= ADC_MR_STARTUP_16; } else if (startup > 0) { - regval = ADC_MR_STARTUP_8; + regval |= ADC_MR_STARTUP_8; } else { - regval = ADC_MR_STARTUP_0; + regval |= ADC_MR_STARTUP_0; } sam_adc_putreg(priv->adc, SAM_ADC_MR, regval); @@ -1291,6 +1353,8 @@ static void sam_tsd_tracking(struct sam_tsd_s *priv, uint32_t time) uint32_t tracktim; uint32_t regval; +#if defined(ATSAMA5D4) + /* Formula for SHTIM is: * * TRACKTIM = (TrackingTime * ADCCLK) / (1000000000) - 1 @@ -1318,7 +1382,11 @@ static void sam_tsd_tracking(struct sam_tsd_s *priv, uint32_t time) tracktim--; } } - +#elif defined (ATSAMA5D3) + tracktim = 0; +#else /* ATSAMA5D2*/ + tracktim = MAX(time, 15); +#endif /* Set the neew TRACKTIM field value int he ADC MR register */ regval = sam_adc_getreg(priv->adc, SAM_ADC_MR); @@ -1338,7 +1406,7 @@ static void sam_tsd_tracking(struct sam_tsd_s *priv, uint32_t time) * * Input Parameters: * priv - A reference to the touchscreen device structure - * time - The new trigger period in nanoseconds + * time - The new trigger period in useconds * * Returned Value: * None @@ -1356,7 +1424,7 @@ static void sam_tsd_trigperiod(struct sam_tsd_s *priv, uint32_t period) * zeroes. */ - div = 100000000; + div = 100000; while (period >= 10 && div >= 10) { period /= 10; @@ -1488,18 +1556,36 @@ static void sam_tsd_initialize(struct sam_tsd_s *priv) { uint32_t regval; +#ifdef SAMA5_TSD_PENDET_TRIG_ALLOWED /* Disable touch trigger */ regval = sam_adc_getreg(priv->adc, SAM_ADC_TRGR); regval &= ~ADC_TRGR_TRGMOD_MASK; regval |= ADC_TRGR_TRGMOD_NOTRIG; sam_adc_putreg(priv->adc, SAM_ADC_TRGR, regval); +#endif /* Setup timing */ sam_tsd_startuptime(priv, BOARD_TSD_STARTUP); sam_tsd_tracking(priv, BOARD_TSD_TRACKTIM); - sam_tsd_trigperiod(priv, 20000000); /* 20ms */ + + /* set trigger mode to be periodic in case ADC not already + * been initialised. It's the only option allowed and that works. + */ + +#ifndef SAMA5_TSD_PENDET_TRIG_ALLOWED + /* if we're allowed to use pendet trigger no need to do this */ + + regval = sam_adc_getreg(priv, SAM_ADC_TRGR); + regval &= ~ADC_TRGR_TRGMOD_MASK; + regval |= ADC_TRGR_TRGMOD_PERIOD; + sam_adc_putreg(priv, SAM_ADC_TRGR, regval); + + sam_tsd_trigperiod(priv, CONFIG_SAMA5_ADC_TRIGGER_PERIOD); +#else + sam_tsd_trigperiod(priv, 20000); /* 20ms */ +#endif /* Setup the touchscreen mode */ @@ -1514,25 +1600,15 @@ static void sam_tsd_initialize(struct sam_tsd_s *priv) regval |= ADC_TSMR_TSMODE_4WIRE; #endif + regval &= ~ADC_TSMR_TSSCTIM_MASK; + regval |= ADC_TSMR_TSSCTIM(BOARD_TSSCTIM); + sam_adc_putreg(priv->adc, SAM_ADC_TSMR, regval); /* Disable averaging */ sam_tsd_setaverage(priv, ADC_TSMR_TSAV_NOFILTER); - /* Select 4-wire w/pressure, 4-wire w/o pressure, or 5 wire modes */ - - regval = sam_adc_getreg(priv->adc, SAM_ADC_TSMR); - regval &= ~ADC_TSMR_TSMODE_MASK; - -#if defined(CONFIG_SAMA5_TSD_5WIRE) - regval |= ADC_TSMR_TSMODE_5WIRE; -#elif defined(CONFIG_SAMA5_TSD_4WIRENPM) - regval |= ADC_TSMR_TSMODE_4WIRENPM; -#else /* if defined(CONFIG_SAMA5_TSD_4WIRE) */ - regval |= ADC_TSMR_TSMODE_4WIRE; -#endif - /* Disable all TSD-related interrupts */ sam_adc_putreg(priv->adc, SAM_ADC_IDR, ADC_TSD_ALLINTS); @@ -1551,6 +1627,7 @@ static void sam_tsd_initialize(struct sam_tsd_s *priv) /* Enable pen contact detection */ + regval = sam_adc_getreg(priv->adc, SAM_ADC_TSMR); regval |= ADC_TSMR_PENDET; sam_adc_putreg(priv->adc, SAM_ADC_TSMR, regval); @@ -1558,14 +1635,36 @@ static void sam_tsd_initialize(struct sam_tsd_s *priv) sam_tsd_debounce(priv, BOARD_TSD_DEBOUNCE); + /* Configure pen sensitivity */ + + regval = sam_adc_getreg(priv->adc, SAM_ADC_ACR); + regval &= ~ADC_ACR_PENDETSENS_MASK; + regval |= ADC_ACR_PENDETSENS(BOARD_TSD_PENDETSENS); +#if defined(ATSAMA5D2) + regval &= ~ADC_ACR_IBCTL_MASK; + regval |= ADC_ACR_IBCTL(BOARD_TSD_IBCTL); +#endif + sam_adc_putreg(priv->adc, SAM_ADC_ACR, regval); + +#ifdef SAMA5_TSD_PENDET_TRIG_ALLOWED /* Configure pen interrupt generation */ regval = sam_adc_getreg(priv->adc, SAM_ADC_TRGR); regval &= ~ADC_TRGR_TRGMOD_MASK; regval |= ADC_TRGR_TRGMOD_PEN; sam_adc_putreg(priv->adc, SAM_ADC_TRGR, regval); +#endif sam_adc_putreg(priv->adc, SAM_ADC_IER, ADC_INT_PEN); + +#ifdef CONFIG_SAMA5_TSD_AUTOCALIB + /* Perform a ts calibration */ + + regval = ADC_CR_TSCALIB | ADC_CR_START; + sam_adc_putreg(priv->adc, SAM_ADC_CR, regval); +#endif + + up_enable_irq(SAM_IRQ_ADC); } /**************************************************************************** @@ -1599,13 +1698,14 @@ static void sam_tsd_uninitialize(struct sam_tsd_s *priv) */ sam_adc_putreg(priv->adc, SAM_ADC_IDR, ADC_TSD_ALLINTS); - +#ifdef SAMA5_TSD_PENDET_TRIG_ALLOWED /* Disable touch trigger */ regval = sam_adc_getreg(priv->adc, SAM_ADC_TRGR); regval &= ~ADC_TRGR_TRGMOD_MASK; regval |= ADC_TRGR_TRGMOD_NOTRIG; sam_adc_putreg(priv->adc, SAM_ADC_TRGR, regval); +#endif /* Disable the touchscreen mode */ @@ -1655,7 +1755,7 @@ int sam_tsd_register(struct sam_adc_s *adc, int minor) /* Initialize the touchscreen device driver instance */ - priv->adc = adc; /* Save the ADC device handle */ + priv->adc = adc; /* Save the ADC device handle */ /* Register the device as an input device */ diff --git a/arch/arm/src/sama5/sam_tsd.h b/arch/arm/src/sama5/sam_tsd.h index 356cd24eed..00e684a671 100644 --- a/arch/arm/src/sama5/sam_tsd.h +++ b/arch/arm/src/sama5/sam_tsd.h @@ -36,8 +36,18 @@ /* Configuration ************************************************************/ -#ifdef CONFIG_SAMA_TSD_RXP -# define CONFIG_SAMA_TSD_RXP 6 +#ifndef CONFIG_SAMA5_TSD_RXP +# define CONFIG_SAMA5_TSD_RXP 6 +#endif + +#ifndef CONFIG_SAMA5_ADC_TRIGGER_PERIOD +# define CONFIG_SAMA5_ADC_TRIGGER_PERIOD 20000 +#endif + +/* Only allow Pendet triggering in limited circumstances */ + +#if defined(CONFIG_SAMA5_ADC_SWTRIG) +# define SAMA5_TSD_PENDET_TRIG_ALLOWED #endif /* Touchscreen interrupt event sets