Better timing
[jelmer/at89prog.git] / at89prog.tex
1 \documentclass[a4paper]{article}
2
3 \usepackage{listings}
4 \usepackage{graphicx}
5 \begin{document}
6
7 \title{Programming the AT89S8252 using SPI}
8 \date{August 5, 2003}
9 \author{Jelmer Vernooij}
10 \maketitle
11
12 \begin{center}
13         Thanks to Hans Tjeerdsma for his help with understanding the datasheets and debugging
14 \end{center}
15
16 \begin{abstract}
17     Copyright \copyright\ 2003  Jelmer Vernooij (jelmer@samba.org).
18         This documentation is distributed under the GNU General Public License (GPL) version 2 or later.
19 \end{abstract}
20
21 \lstset{language=C}
22
23 \tableofcontents
24
25 \section{Introduction}
26
27 The 8051 and 8052 microprocessors are very common processors. Quite some 
28 manufacturers (among them are Intel, Atmel and Analog Devices) produce 8051
29 processors. Personally, I have experience with the Atmel and the Analog Devices
30 processors. 
31
32 Atmel's 8051 processors can be programmed with two different protocols: 
33 a parallel protocol that I will not discuss here, and the SPI protocol. 
34
35 \section{Reasons for writing my own programmer}
36
37 There are several SPI programmers available for the Atmel 8051 series, however
38 only few of them are available for Linux, and none that I could find used 
39 a serial port or had a GUI.
40
41 Available programmers (and reasons not to use them):
42
43 \begin{itemize}
44 \item ponyprog --- has a GUI and is written in C++
45 \item 89prog --- uses the parallel port
46 \item sp89 --- uses the parallel port
47 \item atmel-isp --- only for windows, no source code available
48 \end{itemize}
49
50 And of course, figuring out the protocol with the help of a logic analyser and 
51 some datasheets is a lot of fun...
52
53 \section{The way other manufacturers do it}
54
55 Previously, for my work, I have written a programmer for Analog Devices
56 8051. Their protocol is quite a bit better since it uses the standard RS232
57 protocol. Something that also helps is the fact that their microcontroller 
58 acknowledges or (refuses) commands it gets, while with the AT89 processors, 
59 you just have to guess that the processor understood what you wanted.
60
61 Next to that, Analog Devices provided an example program that could be 
62 used to program the microcontroller of the serial port.
63
64 \section{Other data lines used by the Atmel}
65
66 Next to the lines necessary for SPI, there is another used for putting 
67 the processor in programmable mode:
68
69 \begin{itemize}
70 \item[RST] Reset. Used to put microprocessor in programmable state. Also used to restart running program (by toggling). (Connected to DTR on my board)
71 \end{itemize}
72
73 My own circuit board has uses an additional port that is used to confirm 
74 that CHK has been set.
75
76 When the RST port on the 8051 has been set, the processor listens for SPI 
77 input and handles incoming data.
78
79 \section{The SPI protocol}
80
81 So, what is SPI? SPI is a very simple serial data protocol. This means 
82 that bytes are send serially instead of parallel. SPI is a standard protocol 
83 that is used mainly in embedded devices. It falls in the same family as 
84 $I2C$ or $RS232$.
85
86 As can be read in Atmel's datasheets (document 0401 to be precise), 
87 the SPI protocol uses 3 lines:
88
89 \begin{itemize}
90 \item[MOSI] {\em (Master Out, Slave In)} Data line, in my case sitting on the TxD of my serial port
91 \item[MISO] {\em (Master In, Slave Out)} Data line, controlled by client. (In my case on CTS)
92 \item[SCK] The Clock (in my case on RTS of the serial port)
93 \end{itemize}
94
95 \subsection{How does SPI work?}
96
97 The SPI works with two parties: the slave and the master. The master controls 
98 the line. In my case the personal computer is the master and the 8051 is 
99 the slave. There is another data line ({\em Slave Select}) that is used to select 
100 who the slave is, but I didn't need to use that bit.
101
102 The master sets a bit on the {\em MOSI} and then generates a clock pulse, after 
103 which the next bit is set and another clock pulse is generated, etc.
104
105 \begin{figure}
106 \caption{Sending the bit pattern $0011 0100$ using SPI}
107
108 \includegraphics{SPI1}
109 \end{figure}
110
111 A clock pulse is generated by simply setting the {\em SCK} bit high and then low 
112 again after a few microseconds.
113
114 Here is my {\em SPI\_Out} function:
115
116 \begin{lstlisting}
117
118 void SPI_Out(int b)
119 {
120         int i;
121         for(i = 7; i >= 0; i--) {
122                 if(b & (1 << i)) SetMOSI();
123                 else ClearMOSI();
124                 waitmicrosec(2);
125                 SetSCK();
126                 waitmicrosec(3);
127                 ClearSCK();
128                 waitmicrosec(2);
129         }
130 }
131
132 \end{lstlisting}
133
134 Reading data from the slave is done in a similar way. The server requests 
135 data from the slave, after which it generates clock pulses on which the slave
136 sets the MISO line.
137
138 My {\em SPI\_In} function:
139
140 \begin{lstlisting}
141 int SPI_In()
142 {
143         int i, b = 0;
144         for(i = 7; i >= 0; i--) {
145                 SetSCK();
146                 waitmicrosec(2);
147                 if(GetMISO())b |= 1 << i;
148                 waitmicrosec(3);
149                 ClearSCK();
150                 waitmicrosec(2);
151         }
152         return b;
153 }
154 \end{lstlisting}
155
156 That's basically all that SPI does. It's that simple!
157
158 \section{AT89* commands}
159
160 This section describes the various commands that can be sent 
161 to the 8051 over SPI when it's {\em RST} bit is set.
162
163 \subsection{Enabling program modus}
164
165 Before the 8051 accepts any commands, it needs to be put into command mode.
166 That's what this command is for. Always run this command before you 
167 run any other command.
168
169 \begin{lstlisting}
170 void programming()
171 {
172         /* Send enable serial instruction to MOSI */
173         SPI_Out(0xAC); /* 1010 1100 */
174         SPI_Out(0x53); /* 0101 0011 */
175         SPI_Out(0x00); /* xxxx xxxx (don't care) */
176         waitmillisec(9);
177 }
178 \end{lstlisting}
179
180 \subsection{Erasing code and data memory}
181
182 \begin{lstlisting}
183 void erase()
184 {
185         SPI_Out(0xAC); /* 1010 1100 */
186         SPI_Out(0x04); /* xxxx x100 (x = don't care) */
187         SPI_Out(0x00); /* xxxx xxxx (don't care) */
188         waitmillisec(9);
189 }
190 \end{lstlisting}
191
192
193 \subsection{Writing data to code memory}
194
195 \begin{lstlisting}
196 void writecode(int addr, char b)
197 {
198      /* hhhh h010 */
199         SPI_Out(0x02 | ((addr >> 5) & 0xF8) | ((addr >> 11) & 0x04));
200         SPI_Out(addr & 0xFF); /* llll llll */
201         SPI_Out(b);
202         waitmillisec(6);
203 }
204 \end{lstlisting}
205
206 \subsection{Reading from code memory}
207
208 \begin{lstlisting}
209 int readcode(int addr)
210 {
211     /* hhhh h001 */
212         SPI_Out(0x01 | ((addr >> 5) & 0xF8) | ((addr >> 11) & 0x04));
213         SPI_Out(addr & 0xFF); /* llll llll */
214         return SPI_In();
215 }
216 \end{lstlisting}
217
218 \subsection{Writing to data memory}
219
220 \begin{lstlisting}
221 void writedata(int addr, char b)
222 {
223         SPI_Out(0x06 | ((addr >> 5) & 0xF8));
224         SPI_Out(addr & 0xFF); /* llll llll */
225         SPI_Out(b);
226 }
227 \end{lstlisting}
228
229 \subsection{Reading from data memory}
230 \begin{lstlisting}
231 int readdata(int addr)
232 {
233
234         SPI_Out(0x05 | ((addr >> 5) & 0xF8));
235         SPI_Out(addr & 0xFF); /* llll llll */
236         return SPI_In();
237 }
238 \end{lstlisting}
239
240 \subsection{Locking memory}
241
242 \begin{lstlisting}
243 void lock(int byte)
244 {
245         int mask = 0xff & ~byte;
246
247         SPI_Out(0xAC);          /* 1010 1100 */
248         SPI_Out(mask | 0x07);   /* pqrx x111 */
249         SPI_Out(0);             /* xxxx xxxx */
250         waitmillisec(9);
251 }
252 \end{lstlisting}
253
254 \section{Tips}
255
256 These are some random tips that might be useful when you are interested in
257 implementing the SPI protocol or the 8051 programming that is running over it.
258
259 \begin{itemize}
260 \item Make sure you clear and set the RST line in 
261 the beginning of your program
262 \item Make sure you wait long enough between clock pulses and that 
263 clock pulses are long enough
264 \item A logic analyser is very useful when debugging timing problems
265 \end{itemize}
266
267 \nocite{*}
268
269 \begin{thebibliography}{99}
270 \bibitem{} Atmel: AT89S8252 Datasheet, \emph{http://www.atmel.com/dyn/resources/prod\_documents/doc0401.pdf}
271 \bibitem{} Rob~Melby: Atmel 89 programmer, \emph{http://www.cc.gatech.edu/gvu/ccg/people/rob/software/89prog.tar.gz}
272 \end{thebibliography}
273
274 \end{document}