mk450: code clean up and documentation
[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 left
45  * ~0xFFF far right */
46 uint16_t mk450_gety() {
47
48         int y = xyvalues[1]; 
49         return y;
50 }
51
52 /* X return values (see y) */
53 uint16_t mk450_getx() {
54
55         int x = xyvalues[0];
56         return x;
57 }
58
59 /* Initiate joystock module and DMA */
60 void mk450_init() {
61
62         /* clock prescaler */
63         rsetbitsfrom(RCC_CFGR, 14, 0x3);
64
65         /* Peripherial init */
66         rsetbit(RCC_APB2ENR, 2); // enable GPIOA
67         rwrite(GPIOA_CRL, 0x44444400); // analog input on GPIOA0
68         rsetbit(RCC_APB2ENR, 9); // enable ADC1
69
70         /* DMA init */
71         rsetbit(RCC_AHBENR, 0); // enable clock on DMA1
72         rwrite(DMA_CPAR1, (uint32_t) ADC1_DR);
73         rwrite(DMA_CMAR1, (uint32_t) xyvalues);
74         rwrite(DMA_CNDTR1, 2); // two values X and Y values
75         rsetbitsfrom(DMA_CCR1, 8, 0x1); // 16-bit
76         rsetbitsfrom(DMA_CCR1, 10, 0x1); // 16-bit
77         rsetbit(DMA_CCR1, 7); // memory increment mode
78         rsetbit(DMA_CCR1, 5); // circular mode
79         rsetbit(DMA_CCR1, 0); // channel enable
80         
81         /* Scan mode for two input channels */
82         rsetbitsfrom(ADC1_SQR1, 20, 0x1); // 2 channels
83         rsetbitsfrom(ADC1_SQR3, 0, 0x0); // ADC1_IN0
84         rsetbitsfrom(ADC1_SQR3, 5, 0x1); // ADC1_IN1
85         rsetbit(ADC1_CR1, 8); // scan mode
86         
87         /* Software start and channel config */
88         rsetbitsfrom(ADC1_CR2, 17, 0x7); // swstart config
89         rsetbit(ADC1_CR2, 20); // trigger enable
90         rsetbitsfrom(ADC1_SMPR2, 0, 0x7); // 237 cycles
91         rsetbitsfrom(ADC1_SMPR2, 3, 0x7); // 237 cycles
92         rsetbit(ADC1_CR2, 1); // continious mode
93
94         /* Calibrate */
95         rsetbit(ADC1_CR2, 2); // calibrate
96         _block(50);
97         
98         /* Wakeup TODO: check datasheet for double init */
99         rsetbit(ADC1_CR2, 8); // enable DMA     
100         rsetbit(ADC1_CR2, 0); // enable ADC
101         rsetbit(ADC1_CR2, 22); // swstart go!
102
103 }