3
0
mirror of https://github.com/Qortal/Brooklyn.git synced 2025-02-07 06:44:18 +00:00
Brooklyn/gnuk/chopstx/example-primer2/primer2-ts.c

224 lines
4.1 KiB
C

#include <stdint.h>
#include <stdlib.h>
#include <chopstx.h>
#include "stm32f103.h"
#include "st7732.h"
#include "primer2-ts.h"
/* ADC3 routines. */
#define ADC3_BASE (APB2PERIPH_BASE + 0x3c00)
static struct ADC *const ADC3 = (struct ADC *const)ADC3_BASE;
#define RCC_APB2ENR_ADC3EN 0x8000
#define RCC_APB2RSTR_ADC3RST 0x8000
#define ADC_SR_JEOC 0x0004
#define ADC_CR1_JEOCIE (1 << 7)
#define ADC_CR2_JSWSTART (1 << 21)
#define ADC_CR2_JEXTTRIG (1 << 15)
#define ADC_CR2_JEXTSEL(n) ((n) << 12)
#define ADC_JSQR_NUM_CH(n) (((n) - 1) << 20)
#define ADC_JSQR_JSQ1_N(n) ((n) << 0)
#define ADC_JSQR_JSQ2_N(n) ((n) << 5)
#define ADC_JSQR_JSQ3_N(n) ((n) << 10)
#define ADC_JSQR_JSQ4_N(n) ((n) << 15)
#define ADC_CHANNEL_IN10 10
#define ADC_CHANNEL_IN11 11
#define ADC_CHANNEL_IN12 12
#define ADC_CHANNEL_IN13 13
#define USE_ADC3_INTR 1
#define INTR_REQ_ADC3 47
/*
* Do calibration for ADC3.
*/
void adc3_init (void)
{
RCC->APB2ENR |= RCC_APB2ENR_ADC3EN;
RCC->APB2RSTR = RCC_APB2RSTR_ADC3RST;
RCC->APB2RSTR = 0;
ADC3->CR1 = 0;
ADC3->CR2 = ADC_CR2_ADON;
ADC3->CR2 = ADC_CR2_ADON | ADC_CR2_RSTCAL;
while ((ADC3->CR2 & ADC_CR2_RSTCAL) != 0)
;
ADC3->CR2 = ADC_CR2_ADON | ADC_CR2_CAL;
while ((ADC3->CR2 & ADC_CR2_CAL) != 0)
;
ADC3->CR2 = 0;
RCC->APB2ENR &= ~RCC_APB2ENR_ADC3EN;
}
static chopstx_intr_t adc3_intr;
void
adc3_start (void)
{
RCC->APB2ENR |= RCC_APB2ENR_ADC3EN;
#if USE_ADC3_INTR
ADC3->CR1 = ADC_CR1_SCAN | ADC_CR1_JEOCIE;
#else
ADC3->CR1 = ADC_CR1_SCAN;
#endif
ADC3->CR2 = ADC_CR2_JEXTTRIG | ADC_CR2_JEXTSEL(7) | ADC_CR2_ADON;
ADC3->SMPR1 = 0xfff;
ADC3->SMPR2 = 0;
ADC3->JSQR = (ADC_JSQR_NUM_CH(4) | ADC_JSQR_JSQ4_N(ADC_CHANNEL_IN13)
| ADC_JSQR_JSQ3_N(ADC_CHANNEL_IN12)
| ADC_JSQR_JSQ2_N(ADC_CHANNEL_IN11)
| ADC_JSQR_JSQ1_N(ADC_CHANNEL_IN10));
#if USE_ADC3_INTR
chopstx_claim_irq (&adc3_intr, INTR_REQ_ADC3);
#endif
}
void adc3_conversion (uint32_t *result)
{
/* Start conversion. */
ADC3->CR2 |= ADC_CR2_JSWSTART;
#if USE_ADC3_INTR
chopstx_intr_wait (&adc3_intr);
#else
while (1)
{
chopstx_usec_wait (1000);
if (ADC3->SR & ADC_SR_JEOC)
break;
}
#endif
ADC3->SR &= ~ADC_SR_JEOC;
result[0] = ADC3->JDR1;
result[1] = ADC3->JDR2;
result[2] = ADC3->JDR3;
result[3] = ADC3->JDR4;
/* Stop conversion. */
ADC3->CR2 &= ~ADC_CR2_JSWSTART;
#if USE_ADC3_INTR
chopstx_intr_done (&adc3_intr);
#endif
return;
}
void adc3_stop (void)
{
/* Power off. */
ADC3->CR1 = 0;
ADC3->CR2 = 0;
RCC->APB2ENR &= ~RCC_APB2ENR_ADC3EN;
}
/* Touch screen routines. */
int
ts_pushed (uint32_t u)
{
return (u < 0xc00);
}
#define FILTER_SIZE 8
static void
ts_filter (int buf[FILTER_SIZE][2], int result[2])
{
int s0, s1;
int i;
s0 = 0;
s1 = 0;
for (i = 0; i < FILTER_SIZE; i++)
{
s0 += buf[i][0];
s1 += buf[i][1];
}
result[0] = s0/FILTER_SIZE;
result[1] = s1/FILTER_SIZE;
}
/* Simple model of primer2 touch screen:
Vdd-[R1]-[Ry]-[Rp]-[Rx]-Vss
U D l R
where R1=1k external register, Rx(resp. Ry)=resisitive component on
X(resp. Y) film and Rp=resisitive component of contact point.
Convert [L, R, U, D] to [Rx, Ry, Rp]. */
void
ts_conversion (uint32_t a[], int r[])
{
int l, u, d, ir1;
int x, y, rp;
l = a[0] & 0xfff;
u = a[2] & 0xfff;
d = a[3] & 0xfff;
ir1 = 4096 - u;
/* r1 = 1000 */
x = (1000 * l)/ir1;
y = (1000 * (u - d))/ir1;
rp = (1000 * (d - l))/ir1;
r[0] = x;
r[1] = y;
r[2] = rp;
}
int
ts_adjust (int *r, int *cord)
{
int x, y;
static int buf[FILTER_SIZE][2];
static int i = 0;
static int fill = 0;
if (!r)
{
i = 0;
fill = 0;
return 0;
}
/* TODO: We might need calibration. */
x = (LCD_COLUMN * (r[0] - 0x20))/0x100;
y = (LCD_ROW * (0x1e0 - r[1]))/0x1c0;
if (x < 0)
x = 0;
if (x >= LCD_COLUMN)
x = LCD_COLUMN - 1;
if (y < 0)
y = 0;
if (y >= LCD_ROW)
y = LCD_ROW - 1;
buf[i][0] = x;
buf[i][1] = y;
i++;
if (i >= FILTER_SIZE)
{
i = 0;
fill = 1;
}
if (!fill)
return 0;
ts_filter (buf, cord);
return 1;
}