mk450: documentation, prepare for merge
[cortex-from-scratch] / drivers / mk450_joystick.c
1 /* (CC-BY-NC-SA) ROBIN KRENS - ROBIN @ ROBINKRENS.NL
2  * 
3  * $LOG$
4  * 2019/9/11 - ROBIN KRENS      
5  * Initial version 
6  * 
7  * $DESCRIPTION$
8  * Dual Axis XY Joystick controller
9  * Uses DMA to store converted input channels. The Analog to Digital
10  * converter (ADC1) is in scan mode and continuously monitors input
11  * channel 0 and 1. There is only one busy-wait for initial calibration
12  * of the ADC. The reference voltage here is 3300 mV. For 2500 mV (idle
13  * state of the joystick) this rougly translate to a value of 3100 
14  * (or 0xC1C) in the 12-bit data register (ADC1_DR). 
15  * Active and non-active (or left and right, up or down for the joystick)
16  * are 0x0 and 0xFFF respectively. 
17  * 
18  * $USAGE$
19  * Use getx and gety to get the current X and Y values of the joystick.
20  * How to use for games: TODO (description)
21  *
22  * */
23
24 #include <stdbool.h>
25 #include <stddef.h>
26 #include <stdint.h>
27
28 #include <sys/mmap.h>
29 #include <sys/robsys.h>
30
31 #include <lib/regfunc.h>
32 #include <lib/string.h>
33 #include <lib/tinyprintf.h>
34
35 #include <drivers/mk450_joystick.h>
36
37 /* X and Y values of the joystick 
38  * Updated continiously */
39 uint16_t xyvalues[2] = {0,0};
40
41
42 /* Y return values is 
43  * ~0xC1C mv means y is idle state 
44  * ~0x0 far up
45  * ~0xFFF far down */
46 uint16_t mk450_gety() {
47
48         int y = xyvalues[1]; 
49         return y;
50 }
51
52 /* X return values (see y)
53  * Far right: 0xFFF
54  * Far left: 0x0 */
55 uint16_t mk450_getx() {
56
57         int x = xyvalues[0];
58         return x;
59 }
60
61 /* Initiate joystock module and DMA */
62 void mk450_init() {
63
64         /* clock prescaler */
65         rsetbitsfrom(RCC_CFGR, 14, 0x3);
66
67         /* Peripherial init */
68         rsetbit(RCC_APB2ENR, 2); // enable GPIOA
69         rwrite(GPIOA_CRL, 0x44444400); // analog input on GPIOA0
70         rsetbit(RCC_APB2ENR, 9); // enable ADC1
71
72         /* DMA init */
73         rsetbit(RCC_AHBENR, 0); // enable clock on DMA1
74         rwrite(DMA_CPAR1, (uint32_t) ADC1_DR);
75         rwrite(DMA_CMAR1, (uint32_t) xyvalues);
76         rwrite(DMA_CNDTR1, 2); // two values X and Y values
77         rsetbitsfrom(DMA_CCR1, 8, 0x1); // 16-bit
78         rsetbitsfrom(DMA_CCR1, 10, 0x1); // 16-bit
79         rsetbit(DMA_CCR1, 7); // memory increment mode
80         rsetbit(DMA_CCR1, 5); // circular mode
81         rsetbit(DMA_CCR1, 0); // channel enable
82         
83         /* Scan mode for two input channels */
84         rsetbitsfrom(ADC1_SQR1, 20, 0x1); // 2 channels
85         rsetbitsfrom(ADC1_SQR3, 0, 0x0); // ADC1_IN0
86         rsetbitsfrom(ADC1_SQR3, 5, 0x1); // ADC1_IN1
87         rsetbit(ADC1_CR1, 8); // scan mode
88         
89         /* Software start and channel config */
90         rsetbitsfrom(ADC1_CR2, 17, 0x7); // swstart config
91         rsetbit(ADC1_CR2, 20); // trigger enable
92         rsetbitsfrom(ADC1_SMPR2, 0, 0x7); // 237 cycles
93         rsetbitsfrom(ADC1_SMPR2, 3, 0x7); // 237 cycles
94         rsetbit(ADC1_CR2, 1); // continious mode
95
96         /* Calibrate */
97         rsetbit(ADC1_CR2, 2); // calibrate
98         _block(50);
99         
100         /* Wakeup TODO: check datasheet for double init */
101         rsetbit(ADC1_CR2, 8); // enable DMA     
102         rsetbit(ADC1_CR2, 0); // enable ADC
103         rsetbit(ADC1_CR2, 22); // swstart go!
104
105 }