Abstraction of S3C2440 bare-board program design (no operating system)
In the embedded field, almost all Device Control and various Protocol control are in the same embedded CPU, which is very helpful to abstract the CPU core and device. If we can abstract the control of CPU cores and devices, there is no need to have a deep understanding of CPU when porting OS or developing drivers, you do not need to know what a bit of a register controls or how to initialize a control register.
When writing a bare-board application using a controller, the programmer only needs to understand the initialization sequence and content of the controller, and can complete the application without understanding the initialization details. Obviously, the work efficiency can be greatly improved, and the specific hardware configuration is the most error-prone place in the application, and the use of controllers can greatly reduce the possibility of errors.
Arm is a more powerful single-chip microcomputer. In the process of studying bare metal program design, it is found that arm integrates more peripherals than general single-chip microcomputer (general single-chip microcomputer only integrates the serial port, there are also four sets of I/O Ports), including more gpio and more registers. The registers are set and enabled to control the relevant pins to control the relevant devices. The S3C2440 is integrated with hardware controllers. Various driver protocols are generated using hardware controllers. You only need to configure the registers of the corresponding hardware controllers to generate the corresponding driver sequence. High-end arm learning focuses on software programming (that is, understanding) with rich resources and few need to expand peripherals. The learning focus is on how to configure registers and how to write applications.
Set the corresponding control register to read and write the corresponding data register. The focus of studying bare-board program development is to understand the principles of various interface protocols, so that you can better understand the initialization sequence and initialization content of the controller.
The following uses the S3C2440 I2C controller as an example. The following program is based on the interrupt mode. For details about the I2C protocol, refer to my previous blog. The I2C Protocol stipulates that an ACK should be sent after the receiver receives a byte (address or data), and the sender can then send data or end data transmission after receiving the Ack. The receiver (Here We Are the I2C controller of S3C2440) receives an ACK and an interruption occurs. In the interrupt processing program, you can continue sending the program or stop the transmission. After understanding the basic principles of the I2C protocol, you can easily write programs.
// ================================================ ==============================/// Smdk2440 IIC configuration // gpe15 = iicsda, gpe14 = iicscl // "interrupt mode" for IIC block // ====================== ========================================================== = // ****************** [test_iic] ***************** * ********************* void test_iic (void) {unsigned int I, j, save_e, save_pe; static u8 data [256]; uart_printf ("\ niic test (in Terrupt) using AT24C08 \ n "); save_e = rgpecon; // Save the previous value rgpecon | = 0xa00000; // gpe15: iicsda, gpe14: iiccl Limit = (unsigned) iicint; // set the interrupt handling function rintmsk & = ~ (Bit_iic); // enable IIC interrupt // enable ACK, prescaler iicclk = pclk/16, enable interrupt, transmit clock value TX clock = iicclk/16 // If pclk 50.7 MHz, iicclk = 3.17 MHz, TX clock = 0.198 MHz riiccon = (1 <7) | (0 <6) | (1 <5) | (0xf ); // The fourth digit is 1, the SCL line is low, and the transmission is interrupted. riicadd = 0x10; // 2440 slave address = [7] riicstat = 0x10; // IIC bus data output enable (Rx/Tx) Enable receiving/sending function riiclc = (1 <2) | (1); // filter enable, 15 clocks SDA Output delay added by junon uart_printf ("Write test data into AT24C08 \ n"); for (I = 0; I <256; I ++) wr24c080 (0xa0, (u8) i, I); for (I = 0; I <256; I ++) data [I] = 0; uart_printf ("read test data from AT24C08 \ n "); for (I = 0; I <256; I ++) rd24c080 (0xa0, (u8) I, & (data [I]); // line changed 0 ~ F For (I = 0; I <16; I ++) {for (j = 0; j <16; j ++) uart_printf ("% 2x ", data [I * 16 + J]); uart_printf ("\ n");} rintmsk | = bit_iic; rgpecon = save_e ;} // ************************ [wr24c080] ********** * ***************** void wr24c080 (u32 slvaddr, u32 ADDR, u8 data) {_ iicmode = wrdata; _ iicpt = 0; _ iicdata [0] = (u8) ADDR; _ iicdata [1] = data; _ iicdatacount = 2; riicds = slvaddr; // 0xa0 riicstat = 0xf0; // mastx, start host Transmitter Send S Signal // clearing the pending bit isn't needed because the pending bit has been cleared. While (_ iicdatacount! =-1); // wait for the data to be sent. // start a new transmission, but send only the device address and wait for the response to prove that the previous transmission is complete. The next wr24c080 will start again, and no data is written in this transmission; while (1) {riicds = slvaddr; _ iicstatus = 0x100; riicstat = 0xf0; // mastx, start riiccon = 0xaf; // resumes IIC operation. while (_ iicstatus = 0x100); // wait until the data is sent, and the status register changes. If (! (_ Iicstatus & 0x1) // The last received digit is 0 (ACK signal received) break; // when Ack is pinned to determine the status of the last digit} riicstat = 0xd0; // stop mastx condition riiccon = 0xaf; // resumes IIC operation. delay (1); // wait until stop condtion is in effect. // write is completed .} // ********************* [rd24c080] *************** ********************* void rd24c080 (u32 slvaddr, u32 ADDR, u8 * Data) {_ iicmode = setrdaddr; _ iicpt = 0; _ iicdata [0] = (U8) ADDR; _ iicdatacount = 1; riicds = slvaddr; riicstat = 0xf0; // mastx, start // clearing the pending bit isn't needed because the pending bit has been cleared. while (_ iicdatacount! =-1); _ iicmode = rddata; _ iicpt = 0; _ iicdatacount = 1; riicds = slvaddr; riicstat = 0xb0; // masrx, start riiccon = 0xaf; // resumes IIC operation. while (_ iicdatacount! =-1); * Data = _ iicdata [1];} // your void _ IRQ iicint (void) {u32 iicst, I; rsrcpnd = bit_iic; // clear pending bit rintpnd = bit_iic; iicst = riicstat; If (iicst & 0x8) {}// when bus arbitration is failed. if (iicst & 0x4) {}// when a slave address is matched with iicadd if (iicst & 0x2) {}// when a slave address is 0000000b if (iicst & 0x1) {}// when ack isn't pinned ed switch (_ iicmode) {Case Pollack: _ iicstatus = iicst; break; Case rddata: If (_ iicdatacount --) = 0) {_ iicdata [_ iicpt ++] = riicds; riicstat = 0x90; // stop masrx condition riiccon = 0xaf; // resumes IIC operation. delay (1); // wait until stop condtion is in effect. // too long time... // The pending bit will not be set after issuing stop condition. break;} _ iicdata [_ iicpt ++] = riicds; // the last data has to be read with no ack. if (_ iicdatacount) = 0) riiccon = 0x2f; // resumes IIC operation with Noack. else riiccon = 0xaf; // resumes IIC operation with Ack break; Case wrdata: If (_ iicdatacount --) = 0) {riicstat = 0xd0; // stop mastx condition riiccon = 0xaf; // resumes IIC operation. delay (1); // wait until stop condtion is in effect. // The pending bit will not be set after issuing stop condition. break;} riicds = _ iicdata [_ iicpt ++]; // _ iicdata [0] Has dummy. for (I = 0; I <10; I ++); // for setup time until rising edge of iiccl riiccon = 0xaf; // resumes IIC operation. break; Case setrdaddr: // uart_printf ("[S % d]", _ iicdatacount); If (_ iicdatacount --) = 0) break; // IIC operation is stopped because of iiccon [4] riicds = _ iicdata [_ iicpt ++]; for (I = 0; I <10; I ++ ); // for setup time until rising edge of iiccl riiccon = 0xaf; // resumes IIC operation. break; default: break ;}}