summaryrefslogtreecommitdiffstats
path: root/4094.c
blob: 193c8420f80c6c092e7cd7d80cf07c1862510b2b (plain)
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
/*
 *   74HCT4094 shift register driver
 *
 *   Copyright (C) 2013 Michael Buesch <m@bues.ch>
 *
 *   This program is free software; you can redistribute it and/or
 *   modify it under the terms of the GNU General Public License
 *   version 2 as published by the Free Software Foundation.
 *
 *   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.
 */

#include "4094.h"

#include <avr/io.h>
#include <avr/cpufunc.h>


/* Hardware pin configuration */
#define SR4094_DATA_PORT	PORTB
#define SR4094_DATA_DDR		DDRB
#define SR4094_DATA_BIT		2
#define SR4094_CLOCK_PORT	PORTB
#define SR4094_CLOCK_DDR	DDRB
#define SR4094_CLOCK_BIT	3
#define SR4094_STROBE_PORT	PORTB
#define SR4094_STROBE_DDR	DDRB
#define SR4094_STROBE_BIT	0


void sr4094_put_data(sr4094_t old_state, sr4094_t new_state)
{
	sr4094_t mask = (sr4094_t)1 << (sizeof(sr4094_t) * 8 - 1);
	sr4094_t current_state = old_state;

	if (new_state == old_state) {
		/* Neue Daten sind bereits aktiv. */
		return;
	}

	/* Daten in das Schieberegister laden. */
	SR4094_STROBE_PORT &= ~(1 << SR4094_STROBE_BIT);
	do {
		current_state <<= 1;
		/* Datenpin setzen. */
		if (new_state & mask) {
			SR4094_DATA_PORT |= (1 << SR4094_DATA_BIT);
			current_state |= 1;
		} else
			SR4094_DATA_PORT &= ~(1 << SR4094_DATA_BIT);
		/* Taktflanke ausgeben. */
		SR4094_CLOCK_PORT |= (1 << SR4094_CLOCK_BIT);
		_NOP();
		SR4094_CLOCK_PORT &= ~(1 << SR4094_CLOCK_BIT);
		mask >>= 1;
	} while (new_state != current_state);
	SR4094_STROBE_PORT |= (1 << SR4094_STROBE_BIT);
}

void sr4094_init(void)
{
	/* Ports initialisieren. */
	SR4094_DATA_PORT &= ~(1 << SR4094_DATA_BIT);
	SR4094_DATA_DDR |= (1 << SR4094_DATA_BIT);

	SR4094_CLOCK_PORT &= ~(1 << SR4094_CLOCK_BIT);
	SR4094_CLOCK_DDR |= (1 << SR4094_CLOCK_BIT);

	SR4094_STROBE_PORT |= (1 << SR4094_STROBE_BIT);
	SR4094_STROBE_DDR |= (1 << SR4094_STROBE_BIT);

	/* Alle Bits loeschen. */
	sr4094_put_data((sr4094_t)-1ul, 0);
}
bues.ch cgit interface