forked from urjaman/libfrser
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathspihw_avrspi.c
More file actions
130 lines (109 loc) · 3.07 KB
/
spihw_avrspi.c
File metadata and controls
130 lines (109 loc) · 3.07 KB
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
/*
* This file is part of the libfrser project.
*
* Copyright (C) 2015 Urja Rannikko <urjaman@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "main.h"
#include "spihw_avrspi.h"
#include "frser-cfg.h"
/* This is for the usage of the SPI module of the ATmega88/168/328, maybe others. */
/* Doesnt deal with CS. */
static uint8_t spi_initialized = 0;
#ifdef FRSER_FEAT_SPISPEED
static uint8_t spi_set_spd = 0; /* Max speed - F_CPU/2 */
const uint8_t PROGMEM spd_table[7] = {
0x80, // SPI2X is 0x80 in this table because i say so. - div 2
0, // div 4
0x80 | _BV(SPR0), // div 8
_BV(SPR0), // div 16
0x80 | _BV(SPR1), // div 32
_BV(SPR1), // div64
_BV(SPR1) | _BV(SPR0), //div128
};
const uint32_t PROGMEM spd_hz_table[7] = {
F_CPU/2, F_CPU/4, F_CPU/8, F_CPU/16, F_CPU/32, F_CPU/64, F_CPU/128
};
uint32_t spi_set_speed(uint32_t hz) {
/* We can set F_CPU / : 2,4,8,16,32,64,128 */
uint8_t spd;
uint32_t hz_spd;
/* Range check. */
if (hz<=(F_CPU/128)) {
spd = 6;
hz_spd = F_CPU/128;
} else {
for (spd=0;spd<7;spd++) {
hz_spd = pgm_read_dword(&(spd_hz_table[spd]));
if (hz >= hz_spd) break;
}
}
spi_set_spd = spd;
if (spi_initialized) { // change speed
spi_init(); // re-init
}
return hz_spd;
}
void spi_init(void) {
/* DDR and PORT settings come from elsewhere (maybe flash.c) */
uint8_t spdv = pgm_read_byte(&(spd_table[spi_set_spd]));
SPCR = _BV(SPE) | _BV(MSTR) | (spdv & 0x03);
if (spdv&0x80) SPSR |= _BV(SPI2X);
else SPSR &= ~_BV(SPI2X);
spi_initialized = 1;
}
#else
void spi_init(void) {
/* No speed setting code wanted? Max speed. */
SPCR = _BV(SPE) | _BV(MSTR);
SPSR |= _BV(SPI2X);
spi_initialized = 1;
}
#endif
uint8_t spi_uninit(void) {
if (spi_initialized) {
SPCR = 0;
spi_initialized = 0;
return 1;
}
return 0;
}
void spi_awrite_fast(uint8_t d) {
SPDR = d;
}
void spi_awrite(uint8_t d) {
uint8_t dummy = SPSR; /* Flush previous SPIF */
SPDR = d;
if (SPSR & _BV(WCOL)) {
loop_until_bit_is_set(SPSR,SPIF);
SPDR = d;
}
(void)dummy; /* Silence compiler */
}
uint8_t spi_aread(void) {
loop_until_bit_is_set(SPSR,SPIF);
return SPDR;
}
uint8_t spi_txrx(const uint8_t c) {
spi_awrite_fast(c);
return spi_aread();
}
/* This is here only to keep spi_initialized a static variable,
* hidden from other bits of code. */
void spi_init_cond(void) {
if (!spi_initialized) spi_init();
}
/* Select and deselect are not part of the "domain" of this .c / target-specific */