~ubuntu-branches/ubuntu/gutsy/avr-libc/gutsy

« back to all changes in this revision

Viewing changes to doc/examples/stdiodemo/hd44780.c

  • Committer: Bazaar Package Importer
  • Author(s): Hakan Ardo
  • Date: 2006-11-15 21:12:47 UTC
  • mfrom: (3.1.2 feisty)
  • Revision ID: james.westby@ubuntu.com-20061115211247-b7qhgnb6o49v5zsg
Tags: 1:1.4.5-2
* Convertion to debheler fixed (closes: #398220)
* Reference to /usr/share/common-licenses in copyright file

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * ----------------------------------------------------------------------------
 
3
 * "THE BEER-WARE LICENSE" (Revision 42):
 
4
 * <joerg@FreeBSD.ORG> wrote this file.  As long as you retain this notice you
 
5
 * can do whatever you want with this stuff. If we meet some day, and you think
 
6
 * this stuff is worth it, you can buy me a beer in return.        Joerg Wunsch
 
7
 * ----------------------------------------------------------------------------
 
8
 *
 
9
 * HD44780 LCD display driver
 
10
 *
 
11
 * The LCD controller is used in 4-bit mode with a full bi-directional
 
12
 * interface (i.e. R/~W is connected) so the busy flag can be read.
 
13
 *
 
14
 * $Id: hd44780.c,v 1.1.2.3 2006/10/08 21:51:14 joerg_wunsch Exp $
 
15
 */
 
16
 
 
17
#include "defines.h"
 
18
 
 
19
#include <stdbool.h>
 
20
#include <stdint.h>
 
21
 
 
22
#include <avr/io.h>
 
23
#include <util/delay.h>
 
24
 
 
25
#include "hd44780.h"
 
26
 
 
27
#define GLUE(a, b)     a##b
 
28
#define PORT(x)        GLUE(PORT, x)
 
29
#define PIN(x)         GLUE(PIN, x)
 
30
#define DDR(x)         GLUE(DDR, x)
 
31
 
 
32
#define HD44780_PORTOUT    PORT(HD44780_PORT)
 
33
#define HD44780_PORTIN     PIN(HD44780_PORT)
 
34
#define HD44780_DDR        DDR(HD44780_PORT)
 
35
 
 
36
#define HD44780_DATABITS \
 
37
(_BV(HD44780_D4)|_BV(HD44780_D5)|_BV(HD44780_D6)|_BV(HD44780_D7))
 
38
 
 
39
#define HD44780_BUSYFLAG 0x80
 
40
 
 
41
/*
 
42
 * Send one pulse to the E signal (enable).  Mind the timing
 
43
 * constraints.  If readback is set to true, read the HD44780 data
 
44
 * pins right before the falling edge of E, and return that value.
 
45
 */
 
46
static inline uint8_t
 
47
hd44780_pulse_e(bool readback) __attribute__((always_inline));
 
48
 
 
49
static inline uint8_t
 
50
hd44780_pulse_e(bool readback)
 
51
{
 
52
  uint8_t x;
 
53
 
 
54
  HD44780_PORTOUT |= _BV(HD44780_E);
 
55
  /*
 
56
   * Guarantee at least 500 ns of pulse width.  For high CPU
 
57
   * frequencies, a delay loop is used.  For lower frequencies, NOPs
 
58
   * are used, and at or below 1 MHz, the native pulse width will
 
59
   * already be 1 us or more so no additional delays are needed.
 
60
   */
 
61
#if F_CPU > 4000000UL
 
62
  _delay_us(0.5);
 
63
#else
 
64
  /*
 
65
   * When reading back, we need one additional NOP, as the value read
 
66
   * back from the input pin is sampled close to the beginning of a
 
67
   * CPU clock cycle, while the previous edge on the output pin is
 
68
   * generated towards the end of a CPU clock cycle.
 
69
   */
 
70
  if (readback)
 
71
    __asm__ volatile("nop");
 
72
#  if F_CPU > 1000000UL
 
73
  __asm__ volatile("nop");
 
74
#    if F_CPU > 2000000UL
 
75
  __asm__ volatile("nop");
 
76
  __asm__ volatile("nop");
 
77
#    endif /* F_CPU > 2000000UL */
 
78
#  endif /* F_CPU > 1000000UL */
 
79
#endif
 
80
  if (readback)
 
81
    x = HD44780_PORTIN & HD44780_DATABITS;
 
82
  else
 
83
    x = 0;
 
84
  HD44780_PORTOUT &= ~_BV(HD44780_E);
 
85
 
 
86
  return x;
 
87
}
 
88
 
 
89
/*
 
90
 * Send one nibble out to the LCD controller.
 
91
 */
 
92
static void
 
93
hd44780_outnibble(uint8_t n, uint8_t rs)
 
94
{
 
95
  uint8_t x;
 
96
 
 
97
  HD44780_PORTOUT &= ~_BV(HD44780_RW);
 
98
  if (rs)
 
99
    HD44780_PORTOUT |= _BV(HD44780_RS);
 
100
  else
 
101
    HD44780_PORTOUT &= ~_BV(HD44780_RS);
 
102
  x = (HD44780_PORTOUT & ~HD44780_DATABITS) | ((n << HD44780_D4) & HD44780_DATABITS);
 
103
  HD44780_PORTOUT = x;
 
104
  (void)hd44780_pulse_e(false);
 
105
}
 
106
 
 
107
/*
 
108
 * Send one byte to the LCD controller.  As we are in 4-bit mode, we
 
109
 * have to send two nibbles.
 
110
 */
 
111
void
 
112
hd44780_outbyte(uint8_t b, uint8_t rs)
 
113
{
 
114
  hd44780_outnibble(b >> 4, rs);
 
115
  hd44780_outnibble(b & 0xf, rs);
 
116
}
 
117
 
 
118
/*
 
119
 * Read one nibble from the LCD controller.
 
120
 */
 
121
static uint8_t
 
122
hd44780_innibble(uint8_t rs)
 
123
{
 
124
  uint8_t x;
 
125
 
 
126
  HD44780_PORTOUT |= _BV(HD44780_RW);
 
127
  HD44780_DDR &= ~HD44780_DATABITS;
 
128
  if (rs)
 
129
    HD44780_PORTOUT |= _BV(HD44780_RS);
 
130
  else
 
131
    HD44780_PORTOUT &= ~_BV(HD44780_RS);
 
132
  x = hd44780_pulse_e(true);
 
133
  HD44780_DDR |= HD44780_DATABITS;
 
134
  HD44780_PORTOUT &= ~_BV(HD44780_RW);
 
135
 
 
136
  return (x & HD44780_DATABITS) >> HD44780_D4;
 
137
}
 
138
 
 
139
/*
 
140
 * Read one byte (i.e. two nibbles) from the LCD controller.
 
141
 */
 
142
uint8_t
 
143
hd44780_inbyte(uint8_t rs)
 
144
{
 
145
  uint8_t x;
 
146
 
 
147
  x = hd44780_innibble(rs) << 4;
 
148
  x |= hd44780_innibble(rs);
 
149
 
 
150
  return x;
 
151
}
 
152
 
 
153
/*
 
154
 * Wait until the busy flag is cleared.
 
155
 */
 
156
void
 
157
hd44780_wait_ready(void)
 
158
{
 
159
  while (hd44780_incmd() & HD44780_BUSYFLAG) ;
 
160
}
 
161
 
 
162
/*
 
163
 * Initialize the LCD controller.
 
164
 *
 
165
 * The initialization sequence has a mandatory timing so the
 
166
 * controller can safely recognize the type of interface desired.
 
167
 * This is the only area where timed waits are really needed as
 
168
 * the busy flag cannot be probed initially.
 
169
 */
 
170
void
 
171
hd44780_init(void)
 
172
{
 
173
 
 
174
  HD44780_DDR = _BV(HD44780_RS) | _BV(HD44780_RW) | _BV(HD44780_E)
 
175
    | HD44780_DATABITS;
 
176
 
 
177
  _delay_ms(15);                /* 40 ms needed for Vcc = 2.7 V */
 
178
  hd44780_outnibble(HD44780_FNSET(1, 0, 0) >> 4, 0);
 
179
  _delay_ms(4.1);
 
180
  hd44780_outnibble(HD44780_FNSET(1, 0, 0) >> 4, 0);
 
181
  _delay_ms(0.1);
 
182
  hd44780_outnibble(HD44780_FNSET(1, 0, 0) >> 4, 0);
 
183
 
 
184
  hd44780_outnibble(HD44780_FNSET(0, 1, 0) >> 4, 0);
 
185
  hd44780_wait_ready();
 
186
  hd44780_outcmd(HD44780_FNSET(0, 1, 0));
 
187
  hd44780_wait_ready();
 
188
  hd44780_outcmd(HD44780_DISPCTL(0, 0, 0));
 
189
  hd44780_wait_ready();
 
190
}
 
191