1 |
/*****************************************************
|
2 |
Date : 08.01.2024
|
3 |
Author : stefan h.
|
4 |
Chip type : ATtiny817 / ATtiny817 Xplained Mini
|
5 |
Program type : Application
|
6 |
Clock frequency : 20,000000 MHz
|
7 |
Data Stack size :
|
8 |
*****************************************************/
|
9 |
//------------------------------------- INCLUDE --------------------------------
|
10 |
#include <xc.h> // include processor files - each processor file is guarded.
|
11 |
#include <util/atomic.h>
|
12 |
#include <util/twi.h>
|
13 |
|
14 |
//------------------------------------- DEFINES --------------------------------
|
15 |
#define TRUE 1
|
16 |
#define FALSE 0
|
17 |
#define INVALID -1
|
18 |
#define ON 1
|
19 |
#define OFF 0
|
20 |
#define START 1
|
21 |
#define STOP 0
|
22 |
#define SET 1
|
23 |
#define CLEAR 0
|
24 |
#define TOGGLE 1
|
25 |
#define BOOL signed char
|
26 |
#define CHAR char
|
27 |
#define U8 unsigned char
|
28 |
#define S8 signed char
|
29 |
|
30 |
//-------------------------------------- FUSES ---------------------------------
|
31 |
// ATtiny817 Configuration Bit Settings
|
32 |
|
33 |
FUSES = {
|
34 |
.WDTCFG = 0x08, // WDTCFG {PERIOD=1KCLK, WINDOW=OFF}
|
35 |
.BODCFG = 0xE5, // BODCFG {SLEEP=ENABLED, ACTIVE=ENABLED, SAMPFREQ=1KHz, LVL=BODLEVEL7}
|
36 |
.OSCCFG = 0x7E, // OSCCFG {FREQSEL=20MHZ, OSCLOCK=CLEAR}
|
37 |
.TCD0CFG = 0x00, // TCD0CFG {CMPA=CLEAR, CMPB=CLEAR, CMPC=CLEAR, CMPD=CLEAR, CMPAEN=CLEAR, CMPBEN=CLEAR, CMPCEN=CLEAR, CMPDEN=CLEAR}
|
38 |
.SYSCFG0 = 0xF6, // SYSCFG0 {EESAVE=CLEAR, RSTPINCFG=UPDI, CRCSRC=NOCRC}
|
39 |
.SYSCFG1 = 0xFF, // SYSCFG1 {SUT=64MS}
|
40 |
.APPEND = 0x00, // APPEND {APPEND=User range: 0x0 - 0xFF}
|
41 |
.BOOTEND = 0x00, // BOOTEND {BOOTEND=User range: 0x0 - 0xFF}
|
42 |
};
|
43 |
|
44 |
LOCKBITS = 0xC5; // {LB=NOLOCK}
|
45 |
|
46 |
//------------------------------------ PORTMUX ---------------------------------
|
47 |
/** PortMux
|
48 |
* alternate Pins of TWI0 to Pin A2 and A1
|
49 |
*/
|
50 |
#define PORTMUX_CONFIG PORTMUX.CTRLB = (PORTMUX_TWI0_ALTERNATE_gc)
|
51 |
|
52 |
//------------------------------------- PORT -----------------------------------
|
53 |
/** Port A Configuration Register
|
54 |
* PIN FUNCTION DDR PORT
|
55 |
* PIN7: DIAG input pull-up
|
56 |
* PIN6: NC input pull-up
|
57 |
* PIN5: NC input pull-up
|
58 |
* PIN4: NC input pull-up
|
59 |
* PIN3: NC input pull-up
|
60 |
* PIN2: TWI0 SCL input pull-up (TWI0 config overwrites)
|
61 |
* PIN1: TWI0 SDA input pull-up (TWI0 config overwrites)
|
62 |
* PIN0: RESET input pull-up
|
63 |
**/
|
64 |
#define PORTA_CONFIG PORTA.PIN7CTRL = (PORT_PULLUPEN_bm); \
|
65 |
PORTA.PIN6CTRL = (PORT_PULLUPEN_bm); \
|
66 |
PORTA.PIN5CTRL = (PORT_PULLUPEN_bm); \
|
67 |
PORTA.PIN4CTRL = (PORT_PULLUPEN_bm); \
|
68 |
PORTA.PIN3CTRL = (PORT_PULLUPEN_bm); \
|
69 |
PORTA.PIN2CTRL = (PORT_PULLUPEN_bm); \
|
70 |
PORTA.PIN1CTRL = (PORT_PULLUPEN_bm); \
|
71 |
PORTA.PIN0CTRL = (PORT_PULLUPEN_bm); \
|
72 |
PORTA.OUT = (0x00); \
|
73 |
PORTA.DIR = 0x00
|
74 |
|
75 |
//------------------------------------ CLOCK -----------------------------------
|
76 |
/** Clock Configuration
|
77 |
* CLK_MAIN: 20MHz
|
78 |
* CLK_PER: 2MHz
|
79 |
**/
|
80 |
#define F_CPU 20000000UL
|
81 |
#define CLK_PER 2000000UL
|
82 |
#define UNLOCK_CCP CPU_CCP = CCP_IOREG_gc //System critical I/O register settings are protected from accidental modification. Changes to the protected I/O registers or bits, or execution of protected instructions, are only possible after the CPU writes a signature to the CCP register
|
83 |
#define CLKCTRL_PEN ((1<<CLKCTRL_PEN_bp)&CLKCTRL_PEN_bm)
|
84 |
#define CLKCTRL_PDIV CLKCTRL_PDIV_10X_gc
|
85 |
#define CLKCTRL_LOCKEN ((1<<CLKCTRL_LOCKEN_bp)&CLKCTRL_LOCKEN_bm)
|
86 |
#define CLK_CONFIG UNLOCK_CCP; CLKCTRL.MCLKCTRLB = (CLKCTRL_PDIV | CLKCTRL_PEN); UNLOCK_CCP; CLKCTRL.MCLKLOCK = CLKCTRL_LOCKEN; \
|
87 |
while (!(CLKCTRL.MCLKSTATUS&CLKCTRL_OSC32KS_bm) || !(CLKCTRL.MCLKSTATUS&CLKCTRL_OSC20MS_bm) || (CLKCTRL.MCLKSTATUS&CLKCTRL_SOSC_bm)){}
|
88 |
|
89 |
//------------------------------------- WDT ------------------------------------
|
90 |
/** WDT Configuration
|
91 |
* Reset: 1K cycles (1.0s)
|
92 |
**/
|
93 |
#define WDT_RESET __asm("WDR")
|
94 |
|
95 |
//------------------------------------ TWI -------------------------------------
|
96 |
#define SLAVE_ADDRESS 0x00
|
97 |
#define TWI_CONFIG TWI0.SCTRLA = (TWI_DIEN_bm | TWI_APIEN_bm | TWI_PIEN_bm | TWI_ENABLE_bm); TWI0.SADDR = SLAVE_ADDRESS
|
98 |
#define TWI_ADDRESS_MATCH_IF ((TWI0.SSTATUS & TWI_APIF_bm) && (TWI0.SSTATUS & TWI_AP_bm))
|
99 |
#define TWI_DATA_IF (TWI0.SSTATUS & TWI_DIF_bm)
|
100 |
#define TWI_STOP_IF ((TWI0.SSTATUS & TWI_APIF_bm) && (!(TWI0.SSTATUS & TWI_AP_bm)))
|
101 |
#define TWI_RXACK (!(TWI0.SSTATUS & TWI_RXACK_bm))
|
102 |
// Host wishes to read from client
|
103 |
#define TWI_MRST (TWI0.SSTATUS & TWI_DIR_bm)
|
104 |
//send ACK after receiving data / send requested data
|
105 |
#define TWI_ACK TWI0.SCTRLB = (TWI_ACKACT_ACK_gc | TWI_SCMD_RESPONSE_gc);
|
106 |
//send NACK after receiving data
|
107 |
#define TWI_NACK TWI0.SCTRLB = (TWI_ACKACT_NACK_gc | TWI_SCMD_COMPTRANS_gc);
|
108 |
//switch to the non adressed client mode...
|
109 |
#define TWI_RESET TWI0.SSTATUS |= (TWI_DIF_bm | TWI_APIF_bm); TWI0.SCTRLB = (TWI_SCMD_COMPTRANS_gc);
|
110 |
|
111 |
#define TWI_MRST_SIZE 4
|
112 |
#define TWI_MTSR_SIZE 4
|
113 |
enum {
|
114 |
NO_TRANSACTION = 0,
|
115 |
MRST, //host receive, client transmit
|
116 |
MTSR //host transmit, client receive
|
117 |
};
|
118 |
|
119 |
|
120 |
//----------------------------------- VARIABLES --------------------------------
|
121 |
volatile U8 twi_mrst[TWI_MRST_SIZE];
|
122 |
volatile U8 twi_mtsr[TWI_MTSR_SIZE];
|
123 |
volatile U8 twi_transaction_mode = NO_TRANSACTION; //flag to know if other program parts can alter twi_mrst/twi_mtsr buffers
|
124 |
volatile U8 twi_received = FALSE; //flag for rx handler (e.g. update commands)
|
125 |
volatile U8 twi_transmitted = FALSE; //flag for tx handler (e.g. monitoring output)
|
126 |
|
127 |
//------------------------------------ MAIN ------------------------------------
|
128 |
|
129 |
void main_init(void) {
|
130 |
//disable global interrupt
|
131 |
cli();
|
132 |
|
133 |
CLK_CONFIG;
|
134 |
|
135 |
WDT_RESET;
|
136 |
|
137 |
PORTMUX_CONFIG;
|
138 |
|
139 |
PORTA_CONFIG;
|
140 |
// PORTB_CONFIG;
|
141 |
// PORTC_CONFIG;
|
142 |
|
143 |
TWI_CONFIG;
|
144 |
|
145 |
//enable global interrupts
|
146 |
sei();
|
147 |
}
|
148 |
|
149 |
int main(void) {
|
150 |
main_init();
|
151 |
|
152 |
while (1) {
|
153 |
WDT_RESET;
|
154 |
if (twi_received == TRUE) {
|
155 |
twi_received = FALSE;
|
156 |
if (twi_transaction_mode != MTSR) {
|
157 |
ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
|
158 |
//TODO: rx_handler
|
159 |
}
|
160 |
}
|
161 |
}
|
162 |
if (twi_transmitted == TRUE) {
|
163 |
twi_transmitted = FALSE;
|
164 |
if (twi_transaction_mode != MRST) {
|
165 |
ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
|
166 |
//TODO: tx_handler
|
167 |
}
|
168 |
}
|
169 |
}
|
170 |
}
|
171 |
}
|
172 |
|
173 |
//-------------------------------------- ISR -----------------------------------
|
174 |
ISR(TWI0_TWIS_vect) {
|
175 |
static U8 mrst_cnt = 0;
|
176 |
static U8 mtsr_cnt = 0;
|
177 |
|
178 |
static U8 isFirstByte = TRUE; // to bypass the NACK flag for the first byte in a transaction
|
179 |
|
180 |
//TODO
|
181 |
// if (TWI0.SSTATUS & TWI_COLL_bm) {
|
182 |
// I2C_0_collision_callback();
|
183 |
// return;
|
184 |
// }
|
185 |
//
|
186 |
// if (TWI0.SSTATUS & TWI_BUSERR_bm) {
|
187 |
// I2C_0_bus_error_callback();
|
188 |
// return;
|
189 |
// }
|
190 |
|
191 |
//ADDRESS
|
192 |
if (TWI_ADDRESS_MATCH_IF) {
|
193 |
if (TWI_MRST) {
|
194 |
twi_transaction_mode = MRST;
|
195 |
mrst_cnt = 0;
|
196 |
isFirstByte = TRUE;
|
197 |
} else {
|
198 |
twi_transaction_mode = MTSR;
|
199 |
mtsr_cnt = 0;
|
200 |
}
|
201 |
return;
|
202 |
}
|
203 |
|
204 |
//DATA
|
205 |
if (TWI_DATA_IF) {
|
206 |
if (TWI_MRST) {
|
207 |
// Master wishes to read from slave
|
208 |
if (TWI_RXACK || isFirstByte) {
|
209 |
// Received ACK from master or First byte of transaction
|
210 |
isFirstByte = FALSE;
|
211 |
if (mrst_cnt >= TWI_MRST_SIZE) {
|
212 |
TWI0.SDATA = 0xFF;
|
213 |
} else {
|
214 |
TWI0.SDATA = twi_mrst[mrst_cnt];
|
215 |
mrst_cnt++;
|
216 |
}
|
217 |
TWI_ACK;
|
218 |
} else {
|
219 |
// Received NACK from master
|
220 |
TWI_RESET;
|
221 |
}
|
222 |
} else { // Master wishes to write to slave
|
223 |
twi_mtsr[mtsr_cnt] = TWI0.SDATA;
|
224 |
mtsr_cnt++;
|
225 |
if (mtsr_cnt > TWI_MTSR_SIZE) {
|
226 |
TWI_NACK;
|
227 |
} else {
|
228 |
TWI_ACK;
|
229 |
}
|
230 |
}
|
231 |
return;
|
232 |
}
|
233 |
|
234 |
// STOP
|
235 |
if (TWI_STOP_IF) {
|
236 |
if (twi_transaction_mode == MRST) {
|
237 |
twi_transmitted = TRUE;
|
238 |
} else {
|
239 |
if (mtsr_cnt <= TWI_MTSR_SIZE) {
|
240 |
twi_received = TRUE;
|
241 |
}
|
242 |
}
|
243 |
twi_transaction_mode = NO_TRANSACTION;
|
244 |
TWI_RESET;
|
245 |
return;
|
246 |
}
|
247 |
|
248 |
TWI_RESET;
|
249 |
}
|