Basic functionality for TM1637
[cortex-from-scratch] / drivers / tm1637.c
1 /* (CC-BY-NC-SA) ROBIN KRENS - ROBIN @ ROBINKRENS.NL
2  * 
3  * $LOG$
4  * 2019/7/25 - ROBIN KRENS      
5  * Initial version 
6  * 
7  * $DESCRIPTION$
8  * Basic driver for the TM1637. The TM1637 is 8 segment
9  * ledclock peripheral. Communication is similar to I2C,
10  * but not completely. There is no address selecting.
11  *
12  * Alternative I2C protocol : (W)rite or (R)ead
13  * | Start | ADDRESS | W | ACK/NACK | DATA | ACK/NACK | (d+a*n) | St
14  * | Start | ADDRESS | R | ACK/NACK | DATA | ACK/NACK | (d+a*n) | St
15  *
16  * */
17
18 #include <stdbool.h>
19 #include <stddef.h>
20 #include <stdint.h>
21
22 #include <sys/mmap.h>
23 #include <sys/robsys.h>
24
25 #include <lib/regfunc.h>
26 #include <lib/string.h>
27 #include <lib/stdio.h>
28
29 #include <drivers/tm1637.h>
30
31 #define TIMEOUT 1000
32
33 #define DATASET 0x40
34 #define CONTROL 0x80
35 #define SETADDR 0xC0
36
37 #define DISPLAY_ON      0x8F
38 #define DISPLAY_OFF     0x11
39
40 /* STM32F1 microcontrollers do not provide the ability to pull-up SDA and SCL lines. Their
41 GPIOs must be configured as open-drain. So, you have to add two additional resistors to
42 pull-up I2C lines. Something between 4K and 10K is a proven value.
43 */
44
45 /* BIG ENDIAN! */
46
47 void tm1637_init() {
48
49  /* Program the peripheral input clock in I2C_CR2 Register in order to generate correct timings
50  Configure the clock control registers CCR
51  Configure the rise time register TRIS
52  Program the I2C_CR1 register to enable the peripheral
53
54  ENABLE GPIOB6 and B7*/
55
56  regw_u32(RCC_APB1ENR, 0x1, 21, SETBIT);
57  regw_u32(RCC_APB2ENR, 0x1, 3, SETBIT);
58  // //regw_u8(AFIO_EVCR, 0x89, 0, SETBIT);// set event control register, output on ?
59  
60  regw_u32(GPIOB_CRL, 0xEE444444, 0, OWRITE);
61
62  regw_u32(I2C_CR2, 0x2, 0, OWRITE); //2 MHz 
63  regw_u8(I2C_TRISE, 0x3, 0, OWRITE); // MAX = 1000ns, TPCLK1 = 500ns (+1)
64  regw_u32(I2C_CCR, 0x000A, 0, OWRITE); // standard mode, output 100 kHz (100hz* / perip)
65  
66  regw_u32(I2C_CR1, 0x1, 0, OWRITE); // enable
67
68 }
69
70 static void start_condition() {
71
72         regw_u32(I2C_CR1, 0x1, 8, SETBIT); //start
73
74 }
75
76 static void stop_condition() {
77
78         regw_u32(I2C_CR1, 0x1, 9, SETBIT); //stop
79 }
80
81 static int buf_empty() {
82         int cnt = 0;
83         while(!(*I2C_SR1 & 0x80)) {
84                 cnt++;
85                 if (cnt > TIMEOUT) {
86                         return 0;
87                 }
88         }
89         return 1;
90 }
91
92 int ack_recv() {
93
94         int cnt = 0;
95         while(!(*I2C_SR1 & 0x2)) {
96                 cnt++;
97                 if (cnt > TIMEOUT)
98                         return 0;
99         }
100         uint32_t a = *I2C_SR2;
101         return 1;
102
103 }
104
105 int ack10_recv() {
106
107         int cnt = 0;
108         while(!(*I2C_SR1 & 0x8)) {
109                 cnt++;
110                 if (cnt > TIMEOUT)
111                         return 0;
112         }
113         //uint32_t a = *I2C_SR2;
114         return 1;
115
116 }
117
118 int delay() {
119
120         int a = 0;
121         for (int i = 0; i < TIMEOUT; i++)
122                 a++;
123 }
124
125 void set_brightness(uint8_t degree) {
126
127         // set pulse!
128         start_condition();
129 //      regw_u32(I2C_DR, 0xF0, 0, OWRITE);
130   //      if(!ack10_recv())
131 //              cputs("Error: can not set dummy header");
132
133         regw_u32(I2C_DR, 0xF1, 0, OWRITE);
134         if(!ack_recv())
135                 cputs("TIMEOUT3!");
136         stop_condition();
137
138 }
139
140
141 void tm1637_start() {
142
143 //      regw_u32(I2C_CR1, 0x1, 8, SETBIT);
144 //      uint32_t read_status = *I2C_SR1;
145
146 //      regw_u32(I2C_DR, DATASET, 0, OWRITE); 
147         // conform DATA
148 //      read_status = *I2C_SR1;
149 //      read_status = *I2C_SR2;
150
151
152
153 //      start_condition();
154 //      //uint32_t statusr = *I2C_SR1; // clear start_signal
155 //      regw_u32(I2C_DR, 0x20, 0, OWRITE); // write to address CMD
156 //      if(!ack_recv())
157 //              cputs("TIMEOUT!");
158 //      //statusr = *I2C_SR1;
159 //      //statusr = *I2C_SR2;
160 //      stop_condition();
161 //
162 //      //delay();
163         
164         start_condition();
165         regw_u32(I2C_DR, 0x20, 0, OWRITE); // dummy address
166         if(!ack_recv())
167                 cputs("Error: initiating write command\n");
168
169         stop_condition();
170         
171         delay();
172
173         start_condition();
174         regw_u32(I2C_DR, 0xF0, 0, OWRITE); // dummy header F0 ignored! any value will do as long as last bit is not set
175         if(!ack10_recv())
176                 cputs("Error: dummy addr-10 header not acknowledged\n");
177         regw_u32(I2C_DR, 0x04, 0, OWRITE);
178         if(!ack_recv())
179                 cputs("Error: can't set location\n");
180         regw_u32(I2C_DR, 0x04, 0, OWRITE);
181         if(!buf_empty())
182                 cputs("Error: can't write\n");
183         regw_u32(I2C_DR, 0x08, 0, OWRITE);
184         if(!buf_empty()) 
185                 cputs("Error: can't write\n");
186         regw_u32(I2C_DR, 0x08, 0, OWRITE);
187         if(!buf_empty()) 
188                 cputs("Error: can't write\n");
189         stop_condition();
190
191                         /*
192         regw_u32(I2C_DR, 0x00, 0, OWRITE); // ? dummy address
193         if(!ack_recv())
194                 cputs("TIMEOUTA");
195         regw_u32(I2C_DR, 0x03, 0, OWRITE);
196         if(!buf_empty())
197                 cputs("TIMEOUT2A");
198         regw_u32(I2C_DR, 0xFF, 0, OWRITE);
199         if(!buf_empty())
200                 cputs("TIMEOUT2B"); */
201 //
202 //
203
204         delay();
205         set_brightness(0x00);
206         
207
208 /*      delay();
209
210         start_condition();
211         statusr = *I2C_SR1;
212         regw_u32(I2C_DR, DISPLAY_ON, 0, OWRITE);
213         if(!ack_recv())
214                 cputs("TIMEOUT4!");
215         stop_condition(); */
216
217
218         /* regw_u32(I2C_CR1, 0x1, 8, SETBIT); //start
219         uint32_t read_status = *I2C_SR1; 
220         regw_u32(I2C_DR, 0x40, 0, OWRITE); // write to address CMD
221         read_status = *I2C_SR1;
222         read_status = *I2C_SR2;
223         regw_u32(I2C_CR1, 0x1, 9, SETBIT); //stop
224         read_status = *I2C_SR1;
225
226         regw_u32(I2C_CR1, 0x1, 8, SETBIT); //start
227         read_status = *I2C_SR1;
228         regw_u32(I2C_DR, 0xC1, 0, OWRITE); // segment address
229         read_status = *I2C_SR1;
230         read_status = *I2C_SR2;
231         regw_u32(I2C_DR, 0x7D, 0, OWRITE); // write a six
232
233         regw_u32(I2C_CR1, 0x1, 9, SETBIT); //stop
234         read_status = *I2C_SR1;
235
236         regw_u32(I2C_CR1, 0x1, 8, SETBIT); //start
237         read_status = *I2C_SR1;
238
239         regw_u32(I2C_DR, DISPLAY_ON, 0, OWRITE);
240         read_status = *I2C_SR1;
241         regw_u32(I2C_CR1, 0x1, 9, SETBIT); //stop */
242
243 }
244
245 void tm1637_stop() {
246
247         //regw_u32(I2C_CR1, 0x0, 9, SETBIT);
248 }
249
250
251