1. Trang chủ
  2. » Công Nghệ Thông Tin

HandBooks Professional Java-C-Scrip-SQL part 198 pdf

6 101 0
Tài liệu đã được kiểm tra trùng lặp

Đang tải... (xem toàn văn)

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Định dạng
Số trang 6
Dung lượng 32,91 KB

Các công cụ chuyển đổi và chỉnh sửa cho tài liệu này

Nội dung

Peripherals  7.1 Control and Status Registers  7.2 The Device Driver Philosophy  7.3 A Simple Timer Driver  7.4 Das Blinkenlights, Revisited Each pizza glides into a slot like a

Trang 1

flashBase[UNLOCK2_OFFSET] = FLASH_CMD_UNLOCK2;

flashBase[COMMAND_OFFSET] = FLASH_CMD_BYTE_PROGRAM; /*

* Perform the actual write operation

*/

baseAddress[offset] = data[offset];

/*

* Wait for the operation to complete or time-out

*/

while (((baseAddress[offset] & DQ7) != (data[offset] & DQ7)) &&

!(baseAddress[offset] & DQ5));

if ((baseAddress[offset] & DQ7) != (data[offset] & DQ7))

{

break;

}

}

return (offset);

} /* flashWrite() */

/******************************************************************

****

*

* Function: flashErase()

*

* Description: Erase a block of the Flash memory device

*

* Notes: This function is specific to the AMD 29F010 Flash

* memory In this device, individual sectors may be

* hardware protected If this algorithm encounters

* a protected sector, the erase operation will fail

* without notice

*

* Returns: O on success

* Otherwise -1 indicates failure

*

******************************************************************

****/

int

flashErase(unsigned char * sectorAddress)

{

unsigned char * flashBase = FLASH_BASE;

Trang 2

/*

* Issue the command sequence for sector erase

*/

flashBase[UNLOCK1_OFFSET] = FLASH_CMD_UNLOCK1;

flashBase[UNLOCK2_OFFSET] = FLASH_CMD_UNLOCK2;

flashBase[COMMAND_OFFSET] = FLASH_CMD_ERASE_SETUP;

flashBase[UNLOCK1_OFFSET] = FLASH_CMD_UNLOCK1;

flashBase[UNLOCK2_OFFSET] = FLASH_CMD_UNLOCK2;

*sectorAddress = FLASH_CMD_SECTOR_ERASE;

/*

* Wait for the operation to complete or time-out

*/

while (!(*sectorAddress & DQ7) && !(*sectorAddress & DQ5));

if (!(*sectorAddress & DQ7))

{

return (-1);

}

return (0);

} /* flashErase() */

Of course, this is just one possible way to interface to a Flash memory—and not a particularly advanced one at that In particular, this implementation does not

handle any of the chip's possible errors What if the erase operation never

completes? The function flashErase will just keep spinning its wheels, waiting for

that to occur A more robust implementation would use a software time-out as a backup For example, if the Flash device doesn't respond within twice the

maximum expected time (as stated in the databook), the routine could stop polling and indicate the error to the caller (or user) in some way

Another thing that people sometimes do with Flash memory is to implement a small filesystem Because the Flash memory provides nonvolatile storage that is also rewriteable, it can be thought of as similar to any other secondary storage system, such as a hard drive In the filesystem case, the functions provided by the

driver would be more file-oriented Standard filesystem functions like open, close, read, and write provide a good starting point for the driver's programming

interface The underlying filesystem structure can be as simple or complex as your system requires However, a well-understood format like the File Allocation Table (FAT) structure used by DOS is good enough for most embedded projects

[1] 128 kilobytes is one-eighth of the total 1-megabyte address space

Trang 3

[2] The divisor is simply a binary representation of the coefficients of the

generator polynomial—each of which is either or 1 To make this even more

confusing, the highest-order coefficient of the generator polynomial (always a 1) is left out of the binary representation For example, the polynomial in the first

standard, CCITT, has four nonzero coefficients But the corresponding binary representation has only three 1's in it (bits 12, 5, and 0)

[3] There is one other potential twist called "reflection" that my code does not support You probably won't need that anyway

[4] There is one small difference worth noting here The erase and write cycles take longer than the read cycle So if a read is attempted in the middle of one of those operations, the result will be either delayed or incorrect, depending on the device

Chapter 7 Peripherals

 7.1 Control and Status Registers

 7.2 The Device Driver Philosophy

 7.3 A Simple Timer Driver

 7.4 Das Blinkenlights, Revisited

Each pizza glides into a slot like a circuit board into a computer, clicks into place

as the smart box interfaces with the onboard system of the car The address of the customer is communicated to the car, which computes and projects the optimal route on a heads-up display

—Neal Stephenson, Snow Crash

In addition to the processor and memory, most embedded systems contain a

handful of other hardware devices Some of these devices are specific to the

application domain, while others—like timers and serial ports—are useful in a wide variety of systems The most generically useful of these are often included within the same chip as the processor and are called internal, or on-chip,

peripherals Hardware devices that reside outside the processor chip are, therefore, said to be external peripherals In this chapter we'll discuss the most common software issues that arise when interfacing to a peripheral of either type

7.1 Control and Status Registers

Trang 4

The basic interface between an embedded processor and a peripheral device is a set

of control and status registers These registers are part of the peripheral hardware, and their locations, size, and individual meanings are features of the peripheral For example, the registers within a serial controller are very different from those in a timer/counter In this section, I'll describe how to manipulate the contents of these control and status registers directly from your C/C++ programs

Depending upon the design of the processor and board, peripheral devices are located either in the processor's memory space or within the I/O space In fact, it is common for embedded systems to include some peripherals of each type These are called memory-mapped and I/O-mapped peripherals, respectively Of the two types, memory-mapped peripherals are generally easier to work with and are

increasingly popular

Memory-mapped control and status registers can be made to look just like ordinary variables To do this, you need simply declare a pointer to the register, or block of registers, and set the value of the pointer explicitly For example, if the P2LTCH register from Chapter 2, were memory-mapped and located at physical address

7205Eh, we could have implemented toggleLed entirely in C, as shown below A

pointer to an unsigned short—a 16-bit register—is declared and explicitly

initialized to the address 0x7200:005E From that point on, the pointer to the

register looks just like a pointer to any other integer variable:

unsigned short * pP2LTCH = (unsigned short *) 0x7200005E;

void

toggleLed(void)

{

*pP2LTCH ^= LED_GREEN; /* Read, xor, and modify */

} /* toggleLed() */

Note, however, that there is one very important difference between device registers and ordinary variables The contents of a device register can change without the knowledge or intervention of your program That's because the register contents can also be modified by the peripheral hardware By contrast, the contents of a variable will not change unless your program modifies them explicitly For that reason, we say that the contents of a device register are volatile, or subject to

change without notice

The C/C++ keyword volatile should be used when declaring pointers to device registers This warns the compiler not to make any assumptions about the data

Trang 5

stored at that address For example, if the compiler sees a write to the volatile location followed by another write to that same location, it will not assume that the first write is an unnecessary use of processor time In other words, the keyword volatile instructs the optimization phase of the compiler to treat that variable as though its behavior cannot be predicted at compile time

Here's an example of the use of volatile to warn the compiler about the P2LTCH register in the previous code listing:

volatile unsigned short * pP2LTCH = (unsigned short *) 0x7200005E;

It would be wrong to interpret this statement to mean that the pointer itself is

volatile In fact, the value of the variable pP2LTCH will remain 0x7200005E for the duration of the program (unless it is changed somewhere else, of course)

Rather, it is the data pointed to that is subject to change without notice This is a very subtle point, and it is easy to confuse yourself by thinking about it too much Just remember that the location of a register is fixed, though its contents might not

be And if you use the volatile keyword, the compiler will assume the same

The primary disadvantage of the other type of device registers, I/O-mapped

registers, is that there is no standard way to access them from C or C++ Such registers are accessible only with the help of special machine-language

instructions And these processor-specific instructions are not supported by the C

or C++ language standards So it is necessary to use special library routines or inline assembly (as we did in Chapter 2) to read and write the registers of an I/O-mapped device

7.2 The Device Driver Philosophy

When it comes to designing device drivers, you should always focus on one easily stated goal: hide the hardware completely When you're finished, you want the device driver module to be the only piece of software in the entire system that reads or writes that particular device's control and status registers directly In

addition, if the device generates any interrupts, the interrupt service routine that responds to them should be an integral part of the device driver In this section, I'll explain why I recommend this philosophy and how it can be achieved

Of course, attempts to hide the hardware completely are difficult Any

programming interface you select will reflect the broad features of the device

Trang 6

That's to be expected The goal should be to create a programming interface that would not need to be changed if the underlying peripheral were replaced with

Ngày đăng: 06/07/2014, 03:20