1bee186b741bee527c1e15a0a8167b49417ec546
[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 #include <stdio.h>
24 #include <stdlib.h>
25
26 #include "avr_bitbang.h"
27
28 #include "sim_regbit.h"
29 #include "sim_core.h"
30 #include "avr_ioport.h"
31
32 ///@todo refactor SPI to bitbang
33
34 #define BITBANG_MASK    0xFFFFFFFFUL
35
36 /**
37  * read (sample) data from input pin
38  *
39  * @param p             internal bitbang structure
40  */
41 static void avr_bitbang_read_bit(avr_bitbang_t *p)
42 {
43         avr_ioport_state_t iostate;
44         uint8_t bit = 0;
45
46         if ( !p->enabled )
47                 return;
48
49         // read from HW pin
50         if ( p->p_in.port ) {
51                 avr_ioctl(p->avr, AVR_IOCTL_IOPORT_GETSTATE( p->p_in.port ), &iostate);
52                 bit = ( iostate.pin >> p->p_in.pin ) & 1;
53
54                 if ( p->data_order ) {
55                         // data order: shift right
56                         p->data = (p->data >> 1) | ( bit << (p->buffer_size-1));
57                 } else {
58                         // data order: shift left
59                         p->data = (p->data << 1) | bit;
60                 }
61
62         }
63
64         // module callback
65         if ( p->callback_bit_read ) {
66                 p->callback_bit_read(bit, p->callback_param);
67         }
68
69         // data sanitary
70         p->data = p->data & ~(BITBANG_MASK << p->buffer_size);
71 }
72
73 /**
74  * write data to output pin
75  *
76  * @param p             bitbang structure
77  */
78 static void avr_bitbang_write_bit(avr_bitbang_t *p)
79 {
80         uint8_t bit = 0;
81
82         if ( !p->enabled )
83                 return;
84
85         if ( p->data_order ) {
86                 // data order: shift right
87                 bit = p->data & 1;
88         } else {
89                 // data order: shift left
90                 bit = (p->data >> (p->buffer_size-1)) & 1;
91         }
92
93         // output to HW pin
94         if ( p->p_out.port ) {
95                 avr_raise_irq(avr_io_getirq(p->avr, AVR_IOCTL_IOPORT_GETIRQ( p->p_out.port ), p->p_out.pin), bit);
96         }
97
98         // module callback
99         if ( p->callback_bit_write ) {
100                 p->callback_bit_write(bit, p->callback_param);
101         }
102 }
103
104
105 /**
106  * process clock edges (both: positive and negative edges)
107  *
108  * @param p             bitbang structure
109  *
110  */
111 static void avr_bitbang_clk_edge(avr_bitbang_t *p)
112 {
113         uint8_t phase = (p->clk_count & 1) ^ p->clk_phase;
114         uint8_t clk = (p->clk_count & 1) ^ p->clk_pol;
115
116         if ( !p->enabled )
117                 return;
118
119         // increase clock
120         p->clk_count++;
121         clk ^= 1;
122         phase ^= 1;
123
124         // generate clock output on HW pin
125         if ( p->clk_generate && p->p_clk.port ) {
126                 avr_raise_irq(avr_io_getirq(p->avr, AVR_IOCTL_IOPORT_GETIRQ( p->p_clk.port ), p->p_clk.pin), clk);
127         }
128
129         if ( phase ) {
130                 // read data in
131                 avr_bitbang_read_bit(p);
132
133         } else {
134                 // write data out
135                 avr_bitbang_write_bit(p);
136         }
137
138         if ( p->clk_count >= (p->buffer_size*2) ) {
139                 // transfer finished
140                 if ( p->callback_transfer_finished ) {
141                         p->data = p->callback_transfer_finished(p->data, p->callback_param);
142                 }
143                 p->clk_count = 0;
144         }
145 }
146
147 static avr_cycle_count_t avr_bitbang_clk_timer(struct avr_t * avr, avr_cycle_count_t when, void * param)
148 {
149         avr_bitbang_t * p = (avr_bitbang_t *)param;
150
151         avr_bitbang_clk_edge(p);
152
153         if ( p->enabled )
154                 return when + p->clk_cycles/2;
155         else
156                 return 0;
157 }
158
159 static void avr_bitbang_clk_hook(struct avr_irq_t * irq, uint32_t value, void * param)
160 {
161         avr_bitbang_t * p = (avr_bitbang_t *)param;
162         uint8_t clk = (p->clk_count & 1) ^ p->clk_pol;
163
164         // no clock change
165         if ( clk == value )
166                 return;
167
168         avr_bitbang_clk_edge(p);
169 }
170
171 /**
172  * reset bitbang sub-module
173  *
174  * @param avr   avr attached to
175  * @param p             bitbang structure
176  */
177 void avr_bitbang_reset(avr_t *avr, avr_bitbang_t * p)
178 {
179         p->avr = avr;
180         p->enabled = 0;
181         p->clk_count = 0;
182         p->data = 0;
183
184         if ( p->buffer_size < 1 || p->buffer_size > 32 ) {
185                 fprintf(stderr,
186                         "Error: bitbang buffer size should be between 1 and 32. set value: %d\n", p->buffer_size);
187                 abort();
188         }
189
190 }
191
192 /**
193  * start bitbang transfer
194  *
195  * buffers should be written / cleared in advanced
196  * timers and interrupts are connected
197  *
198  * @param p                     bitbang structure
199  */
200 void avr_bitbang_start(avr_bitbang_t * p)
201 {
202         p->enabled = 1;
203         p->clk_count = 0;
204
205         if ( p->clk_phase == 0 ) {
206                 // write first bit
207                 avr_bitbang_write_bit(p);
208         }
209
210         if ( p->clk_generate ) {
211                 // master mode, generate clock -> set timer
212                 avr_cycle_timer_register(p->avr, (p->clk_cycles/2), avr_bitbang_clk_timer, p);
213         } else {
214                 // slave mode -> attach clock function to clock pin
215                 ///@todo test
216                 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);
217         }
218
219 }
220
221
222 /**
223  * stop bitbang transfer
224  *
225  * timers and interrupts are disabled
226  *
227  * @param p                     bitbang structure
228  */
229 void avr_bitbang_stop(avr_bitbang_t * p)
230 {
231
232         p->enabled = 0;
233         avr_cycle_timer_cancel(p->avr, avr_bitbang_clk_timer, p);
234         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);
235 }