1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
|
#include "ds1302.h"
#include <stdio.h>
#include <time.h>
uint8_t ds1302_readAddress(uint8_t address) {
return address | 0x01;
}
void ds1302_spi_session_start(struct ds1302_spi_session * session) {
/*Setup Pins*/
bcm2835_gpio_fsel(session->clock, BCM2835_GPIO_FSEL_OUTP);
bcm2835_gpio_fsel(session->select, BCM2835_GPIO_FSEL_OUTP);
bcm2835_gpio_fsel(session->io, BCM2835_GPIO_FSEL_OUTP);
bcm2835_gpio_write(session->clock, LOW);
bcm2835_delayMicroseconds(10);
bcm2835_gpio_write(session->select, HIGH);
bcm2835_gpio_write(session->io, LOW);
bcm2835_delayMicroseconds(10);
}
void ds1302_spi_session_end(struct ds1302_spi_session * session) {
bcm2835_gpio_write(session->select, LOW);
bcm2835_delayMicroseconds(10);
}
void ds1302_spi_session_write(struct ds1302_spi_session * session, int8_t value) {
bcm2835_gpio_fsel(session->io, BCM2835_GPIO_FSEL_OUTP);
for(int i = 0; i < 8; i++) {
/*The LSB is written first*/
uint8_t out = value & 0x01;
value = value >> 1;
uint8_t o;
if(out != 0x0)
o = HIGH;
else
o = LOW;
/*ds1302 reads the value while the clock is high. Ensure that value is written*/
bcm2835_gpio_write(session->io, o);
bcm2835_delayMicroseconds(DS1302_CLOCKDELAY);
bcm2835_gpio_write(session->clock, HIGH);
/*TODO: Lookup the required wait time*/
bcm2835_delayMicroseconds(DS1302_CLOCKDELAY);
bcm2835_gpio_write(session->clock, LOW);
}
}
uint8_t ds1302_spi_session_read(struct ds1302_spi_session * session) {
bcm2835_gpio_fsel(session->io, BCM2835_GPIO_FSEL_INPT);
uint8_t value = 0;
/*The LSB is read first*/
for(int i = 0; i < 8; i++) {
value = value >> 1 | bcm2835_gpio_lev(session->io) << 7;
bcm2835_gpio_write(session->clock, HIGH);
bcm2835_delayMicroseconds(DS1302_CLOCKDELAY);
bcm2835_gpio_write(session->clock, LOW);
//bcm2835_delayMicroseconds(DS1302_CLOCKDELAY);
}
return value;
}
uint8_t ds1302_set_writeprotect(struct ds1302_spi_session * session, uint8_t protect) {
if(protect != 0x0)
protect = 0x80;
ds1302_spi_session_write(session, DS1302_WRITE_PROTECT);
ds1302_spi_session_write(session, protect);
}
uint8_t ds1302_read_register(struct ds1302_spi_session * session, uint8_t address) {
ds1302_spi_session_write(session, ds1302_readAddress(address));
return ds1302_spi_session_read(session);
}
void ds1302_write_register(struct ds1302_spi_session * session, uint8_t address, uint8_t data) {
ds1302_spi_session_write(session, address);
ds1302_spi_session_write(session, data);
}
uint8_t ds1302_burst_read(struct ds1302_spi_session * session, ds1302BurstType type, uint8_t * output, size_t size) {
if(size <= 0)
return 0;
uint8_t command = ds1302_readAddress(DS1302_CLOCK_BURST);
uint8_t bytesRead = 0;
if(type == DS1302_MEMORY)
command = command | 0x40;
ds1302_spi_session_write(session, command);
/*read more about burst reads from memory*/
for(int i = 0; i < size && i < 9; i++) {
output[i] = ds1302_spi_session_read(session);
bytesRead++;
}
/*Pull the select line down to signal that we are done reading*/
bcm2835_gpio_write(session->select, LOW);
bcm2835_delayMicroseconds(10);
bcm2835_gpio_write(session->select, HIGH);
return bytesRead;
}
uint8_t ds1302_burst_write(struct ds1302_spi_session * session, ds1302BurstType type, uint8_t * input, size_t size) {
if(size <= 0)
return 0;
uint8_t command = DS1302_CLOCK_BURST;
uint8_t bytesWritten = 0;
if(type == DS1302_MEMORY)
command = command | 0x40;
ds1302_spi_session_write(session, command);
for(int i = 0; i < size; i++) {
ds1302_spi_session_write(session, input[i]);
bytesWritten++;
}
/*Pull the select line down to signal that we are done writing*/
bcm2835_gpio_write(session->select, LOW);
bcm2835_delayMicroseconds(10);
bcm2835_gpio_write(session->select, HIGH);
return bytesWritten;
}
/*Convert the base 10 hex representation to just base 10
The upper half represents the tens digit and the lower half
represents the ones digit.
Make sure to clear any bits that are not used in the representation.
(EG the 12/24 and AM/PM bits for the hour register)
*/
uint8_t ds1302_convertToDecimal(uint8_t input) {
uint8_t result = 0x0;
result = ((input >> 4) * 10) + (input & 0x0F);
return result;
}
/*Convert base 10 to the 10 hex representation
Inverse of ds1302_convertToDecimal
*/
uint8_t ds1302_convertToDecimalHex(uint8_t input) {
uint8_t result = 0x0;
uint8_t tens = input / 10;
uint8_t ones = input - (tens * 10);
result = (tens << 4) | ones;
return result;
}
void ds1302_getCalendarTime(struct ds1302_spi_session * session, struct tm * date) {
uint8_t data[7] = {0xff};
/*Clock hour format: High: 12hr, Low: 24h*/
uint8_t h12;
/*PM or AM: High: PM, Low: AM*/
uint8_t pm;
uint8_t hour;
ds1302_burst_read(session, DS1302_REGISTER, data, 7);
date->tm_sec = ds1302_convertToDecimal(data[0] & (~0x80));
date->tm_min = ds1302_convertToDecimal(data[1] & (~0x80));
/*struct tm represents hours in 24 format. Convert the 12hr clock to 24hr*/
h12 = data[2] & 0x80;
pm = data[2] & 0x20;
hour = ds1302_convertToDecimal(data[2] & 0x1F);
if(h12) {
if(pm) {
date->tm_hour = hour + 11;
} else {
date->tm_hour = hour - 1;
}
} else {
date->tm_hour = hour;
}
date->tm_mday = ds1302_convertToDecimal(data[3]);
/*struct tm starts counting from 0 whereas the ds1302 starts from 1*/
date->tm_mon = ds1302_convertToDecimal(data[4]) - 1;
/*struct tm starts counting from 0 whereas the ds1302 starts from 1*/
date->tm_wday = ds1302_convertToDecimal(data[5]) - 1;
/*Number of year that have passed since 1900*/
date->tm_year = (ds1302_convertToDecimal(data[6]) + DS1302_START_YEAR) - 1900;
}
void ds1302_setCalendarTime(struct ds1302_spi_session * session, struct tm * date) {
/*TODO: disable Write protect*/
uint8_t data[8] = {0};
uint8_t hour = 0;
data[0] = ds1302_convertToDecimalHex(date->tm_sec);
data[1] = ds1302_convertToDecimalHex(date->tm_min);
data[2] = ds1302_convertToDecimalHex(date->tm_hour);
data[3] = ds1302_convertToDecimalHex(date->tm_mday);
data[4] = ds1302_convertToDecimalHex(date->tm_mon + 1);
data[5] = ds1302_convertToDecimalHex(date->tm_wday + 1);
data[6] = ds1302_convertToDecimalHex((date->tm_year + 1900) - DS1302_START_YEAR);
data[7] = 0x00;
ds1302_burst_write(session, DS1302_REGISTER, data, 8);
}
|