Makefiles: Separate simavr.pc and simavr-avr.pc
[simavr] / simavr / sim / avr_bitbang.c
1 /*
2         avr_bitbang.c
3
4         Copyright 2008, 2009 Michel Pollet <buserror@gmail.com>
5                           2011 Stephan Veigl <veig@gmx.net>
6
7         This file is part of simavr.
8
9         simavr is free software: you can redistribute it and/or modify
10         it under the terms of the GNU General Public License as published by
11         the Free Software Foundation, either version 3 of the License, or
12         (at your option) any later version.
13
14         simavr is distributed in the hope that it will be useful,
15         but WITHOUT ANY WARRANTY; without even the implied warranty of
16         MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17         GNU General Public License for more details.
18
19         You should have received a copy of the GNU General Public License
20         along with simavr.  If not, see <http://www.gnu.org/licenses/>.
21  */
22
23 #ifndef __AVR_BITBANG_H__
24 #define __AVR_BITBANG_H__
25
26 #ifdef __cplusplus
27 extern "C" {
28 #endif
29
30 #include <stdio.h>
31 #include <stdlib.h>
32
33 #include "avr_bitbang.h"
34
35 #include "sim_regbit.h"
36 #include "sim_core.h"
37 #include "avr_ioport.h"
38
39 ///@todo refactor SPI to bitbang
40
41 #define BITBANG_MASK    0xFFFFFFFFUL
42
43 /**
44  * read (sample) data from input pin
45  *
46  * @param p             internal bitbang structure
47  */
48 static void avr_bitbang_read_bit(avr_bitbang_t *p)
49 {
50         avr_ioport_state_t iostate;
51         uint8_t bit = 0;
52
53         if ( !p->enabled )
54                 return;
55
56         // read from HW pin
57         if ( p->p_in.port ) {
58                 avr_ioctl(p->avr, AVR_IOCTL_IOPORT_GETSTATE( p->p_in.port ), &iostate);
59                 bit = ( iostate.pin >> p->p_in.pin ) & 1;
60
61                 if ( p->data_order ) {
62                         // data order: shift right
63                         p->data = (p->data >> 1) | ( bit << (p->buffer_size-1));
64                 } else {
65                         // data order: shift left
66                         p->data = (p->data << 1) | bit;
67                 }
68
69         }
70
71         // module callback
72         if ( p->callback_bit_read ) {
73                 p->callback_bit_read(bit, p->callback_param);
74         }
75
76         // data sanitary
77         p->data = p->data & ~(BITBANG_MASK << p->buffer_size);
78 }
79
80 /**
81  * write data to output pin
82  *
83  * @param p             bitbang structure
84  */
85 static void avr_bitbang_write_bit(avr_bitbang_t *p)
86 {
87         uint8_t bit = 0;
88
89         if ( !p->enabled )
90                 return;
91
92         if ( p->data_order ) {
93                 // data order: shift right
94                 bit = p->data & 1;
95         } else {
96                 // data order: shift left
97                 bit = (p->data >> (p->buffer_size-1)) & 1;
98         }
99
100         // output to HW pin
101         if ( p->p_out.port ) {
102                 avr_raise_irq(avr_io_getirq(p->avr, AVR_IOCTL_IOPORT_GETIRQ( p->p_out.port ), p->p_out.pin), bit);
103         }
104
105         // module callback
106         if ( p->callback_bit_write ) {
107                 p->callback_bit_write(bit, p->callback_param);
108         }
109 }
110
111
112 /**
113  * process clock edges (both: positive and negative edges)
114  *
115  * @param p             bitbang structure
116  *
117  */
118 static void avr_bitbang_clk_edge(avr_bitbang_t *p)
119 {
120         uint8_t phase = (p->clk_count & 1) ^ p->clk_phase;
121         uint8_t clk = (p->clk_count & 1) ^ p->clk_pol;
122
123         if ( !p->enabled )
124                 return;
125
126         // increase clock
127         p->clk_count++;
128         clk ^= 1;
129         phase ^= 1;
130
131         // generate clock output on HW pin
132         if ( p->clk_generate && p->p_clk.port ) {
133                 avr_raise_irq(avr_io_getirq(p->avr, AVR_IOCTL_IOPORT_GETIRQ( p->p_clk.port ), p->p_clk.pin), clk);
134         }
135
136         if ( phase ) {
137                 // read data in
138                 avr_bitbang_read_bit(p);
139
140         } else {
141                 // write data out
142                 avr_bitbang_write_bit(p);
143         }
144
145         if ( p->clk_count >= (p->buffer_size*2) ) {
146                 // transfer finished
147                 if ( p->callback_transfer_finished ) {
148                         p->data = p->callback_transfer_finished(p->data, p->callback_param);
149                 }
150                 p->clk_count = 0;
151         }
152 }
153
154 static avr_cycle_count_t avr_bitbang_clk_timer(struct avr_t * avr, avr_cycle_count_t when, void * param)
155 {
156         avr_bitbang_t * p = (avr_bitbang_t *)param;
157
158         avr_bitbang_clk_edge(p);
159
160         if ( p->enabled )
161                 return when + p->clk_cycles/2;
162         else
163                 return 0;
164 }
165
166 static void avr_bitbang_clk_hook(struct avr_irq_t * irq, uint32_t value, void * param)
167 {
168         avr_bitbang_t * p = (avr_bitbang_t *)param;
169         uint8_t clk = (p->clk_count & 1) ^ p->clk_pol;
170
171         // no clock change
172         if ( clk == value )
173                 return;
174
175         avr_bitbang_clk_edge(p);
176 }
177
178 /**
179  * reset bitbang sub-module
180  *
181  * @param avr   avr attached to
182  * @param p             bitbang structure
183  */
184 void avr_bitbang_reset(avr_t *avr, avr_bitbang_t * p)
185 {
186         p->avr = avr;
187         p->enabled = 0;
188         p->clk_count = 0;
189         p->data = 0;
190
191         if ( p->buffer_size < 1 || p->buffer_size > 32 ) {
192                 AVR_LOG(avr, LOG_ERROR,
193                                 "Error: bitbang buffer size should be between 1 and 32. set value: %d\n", p->buffer_size);
194                 abort();
195         }
196
197 }
198
199 /**
200  * start bitbang transfer
201  *
202  * buffers should be written / cleared in advanced
203  * timers and interrupts are connected
204  *
205  * @param p                     bitbang structure
206  */
207 void avr_bitbang_start(avr_bitbang_t * p)
208 {
209         p->enabled = 1;
210         p->clk_count = 0;
211
212         if ( p->clk_phase == 0 ) {
213                 // write first bit
214                 avr_bitbang_write_bit(p);
215         }
216
217         if ( p->clk_generate ) {
218                 // master mode, generate clock -> set timer
219                 avr_cycle_timer_register(p->avr, (p->clk_cycles/2), avr_bitbang_clk_timer, p);
220         } else {
221                 // slave mode -> attach clock function to clock pin
222                 ///@todo test
223                 avr_irq_register_notify( avr_io_getirq(p->avr, AVR_IOCTL_IOPORT_GETIRQ( p->p_clk.port ), p->p_clk.pin), avr_bitbang_clk_hook, p);
224         }
225
226 }
227
228
229 /**
230  * stop bitbang transfer
231  *
232  * timers and interrupts are disabled
233  *
234  * @param p                     bitbang structure
235  */
236 void avr_bitbang_stop(avr_bitbang_t * p)
237 {
238
239         p->enabled = 0;
240         avr_cycle_timer_cancel(p->avr, avr_bitbang_clk_timer, p);
241         avr_irq_unregister_notify( avr_io_getirq(p->avr, AVR_IOCTL_IOPORT_GETIRQ( p->p_clk.port ), p->p_clk.pin), avr_bitbang_clk_hook, p);
242 }
243
244 #ifdef __cplusplus
245 };
246 #endif
247
248 #endif /*__AVR_BITBANG_H__*/