File: csinglepincomm.c

package info (click to toggle)
simulavr 1.0.0%2Bgit20160221.e53413b-1
  • links: PTS
  • area: main
  • in suites: buster
  • size: 5,748 kB
  • sloc: cpp: 35,491; python: 6,991; ansic: 3,567; makefile: 1,072; sh: 653; asm: 414; tcl: 320
file content (200 lines) | stat: -rw-r--r-- 5,420 bytes parent folder | download | duplicates (2)
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
// Copyright (C) 2009 Onno Kortmann <onno@gmx.net>
//  
// 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 Street, Fifth Floor, Boston, MA 02110-1301 USA..
//  
//-----------------------------------------------------------------------------
//
// IMPORTANT NOTE: This file is only to illustrate the simulavrxx<->verilog
// interface and is by no means any reference for anything whatsoever!  It
// probably contains lots of bugs! As already stated above, there is no
// warranty!
//
//-----------------------------------------------------------------------------
#include <avr/io.h>
#include <avr/interrupt.h>
#include "csinglepincomm.h"
#define F_CPU 12000000
// Port definition for SPC
// NOTE: DO NOT CHANGE THESE EASILY, THE TIMER OUTPUT PINS ARE USED
// SO CHANGING THE PINS IS USUALLY NOT AN OPTION!
#define SPC_PORT	PORTB
#define SPC_DDR		DDRB
#define SPC_PIN		PINB
#define SPC_BIT		PB3

// Constant to delay the short delay (t_s), initial value. In clock ticks */
#define SPC_INITIAL_DELAY	1500

// Initial multiplier N to go from t_s to t_l:	 t_l=N*t_s */
 #define SPC_LONG_DELAY		3

// loop cycles to wait for receive signal
#define SPC_RX_TIMEOUT		20000

// minimum distance between the high and the low count, in number of counts of
// the smaller value
#define SPC_MINIMUM_DISTANCE	2

// Interrupt blocking?
#if SPC_CLISEI
#define NCLI			cli()
#define NSEI			sei()
#else
#define NCLI			
#define NSEI
#endif

uint16_t spc_delay=SPC_INITIAL_DELAY;
uint8_t spc_multiplier=SPC_LONG_DELAY;
uint8_t spc_mindistance=SPC_MINIMUM_DISTANCE;

void spc_init() {
    // enable pull up
    SPC_PORT|=_BV(SPC_BIT);
}

uint8_t spc_trx_bit(uint8_t bit) {
    uint16_t timeout, high_time, low_time;
    uint16_t spc_long_delay=spc_delay * spc_multiplier;
    // ------------------------------------------------------------
    // --- TRANSMIT                                             ---
    // ------------------------------------------------------------
    NCLI;
    TCCR1B=0; // stop counter
    // timer preparation
    
    // force compare-match into high state
    TCCR1A=_BV(COM1A1)|_BV(COM1A0); // set PB3 on compare match
    TCCR1C=_BV(FOC1A); // force output compare
    // set high state of comp.match on output (should be just pullup before)
    SPC_DDR|=_BV(SPC_BIT);
    TCCR1A=_BV(COM1A1); // clear PB3 on compare match
    TIFR|=_BV(OCF1A); // clear comp.match
    
    // set time until zero
    if (bit)
	OCR1A=spc_long_delay;
    else
	OCR1A=spc_delay;
	    
    // reset counter
    TCNT1=0;

     // and apply full system clock timer1
    TCCR1B=_BV(CS10);
    NSEI;
    
    // wait until high part has been sent
    while (! (TIFR & _BV(OCF1A)));

    NCLI;
    TCCR1B=0; // stop  counter
    TCCR1A=_BV(COM1A1)|_BV(COM1A0); // set PB3 on compare match
    TIFR|=_BV(OCF1A); // clear comp.match

    // set time until one
    if (bit)
	OCR1A=spc_delay;
    else
	OCR1A=spc_long_delay;

    // reset counter
    TCNT1=0;

    TCCR1B=_BV(CS10); // start counter
    NSEI;
    
    // wait until low part has been sent
    while (! (TIFR & _BV(OCF1A)));
    NCLI;
    //TIFR|=_BV(OCF1A); // clear comp.match
    // ------------------------------------------------------------
    // --- RECEIVE                                              ---
    // ------------------------------------------------------------
    // go back to normal port mode on PB3
    TCCR1A=0;
    SPC_DDR&=~_BV(SPC_BIT);

    OCR1A=0x0000; // 'disable' OCR1A

    NSEI;
    
    /* stop and clear counter, set noise canceler bit,
       get ready for input capture. */
    TCNT1=0;
    TIFR|=_BV(ICF1);
    TCCR1B=_BV(CS10)|_BV(ICNC1); 
    NSEI;

    // wait for falling edge
    timeout=0;
    while (! (TIFR & _BV(ICF1))) {
	if (timeout == SPC_RX_TIMEOUT)
	    return 2;
	timeout++;
    }
    NCLI;
    high_time=ICR1; // read that value
    // get ready for another round, raising edge now
    TCCR1B=_BV(CS10)|_BV(ICNC1)|_BV(ICES1);
    TIFR|=_BV(ICF1); 
    NSEI;

    // wait for rising edge
    timeout=0;
    while (! (TIFR & _BV(ICF1))) {
	if (timeout == SPC_RX_TIMEOUT)
	    return 2;
	timeout++;
    }

    NCLI;
    low_time=ICR1-high_time; // read that value, too
    NSEI;

    if (high_time>low_time) {
	if (high_time<low_time * spc_mindistance)
	    return 2;
	else return 1;
    } else {
	if (low_time<high_time * spc_mindistance)
	    return 2;
	else return 0;
    }
}

    
uint16_t spc_trx(uint8_t val) {
    uint8_t res;
    uint8_t i;
    uint8_t rxbit;
    
    // send start bit
    i=spc_trx_bit(0);

    if (i) // timeout or 'one' bit?
	return 0x100 * i;

    // main TRX loop
    res=0;
    for (i=0; i < 8; i++) {
	rxbit=spc_trx_bit(val & 0x01);
	if (rxbit>1)
	    return 0x100 * rxbit; // timeout or framing error!
	if (rxbit) res|=1<<i;
	val>>=1;
    }
    return res;
}