Survey
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
Sea Glider Development and Power Characterization Sean Lastuka EE542 Final Report December 8, 2007 University of Washington Table of Contents 1. Sea Glider Background 2 2. Sea Glider Design 3 3. Project Overview 4 a. Linux Installation 5 b. Serial Port Operation 8 c. SD Card Operation 9 d. Power Characterization 9 4. Conclusion and Final Thoughts 11 5. References 13 6. Code Appendix 14 1 Sea Glider Background The Sea Glider is an autonomous underwater vehicle (AUV). It is used in scientific, military and burgeoning commercial roles. It is used as a mobile platform equipped with sensors that monitor salinity, water temperature, pressure, acoustics and other ocean related characteristics. Some primary considerations in Sea Glider design include mission duration, electrical sensor load, maximum depth rating, forward velocity and cargo capacity. To travel forward, the Sea Glider must alternatively sink and rise through the water column, see Figure 1. The rising and falling motions create a hydrodynamic effect on the wings of the Sea Glider to promote forward motion. Through this effect, a Sea Glider travels horizontally through the water at a speed of approximately one foot per second. The primary component that enables the sea glider to rise and fall through the water is a variable buoyancy device (VBD). This device is mounted on the Sea Glider’s fuselage as shown in Figure 2. It effectively changes the density of the Sea Glider. When the density of the VBD is reduced, the Sea Glider rises. Alternatively, when the density increases, the Sea Glider sinks... like a rock. Figure 1: Sea Glider motion. A sinking glider has high density, and a rising glider has low density. 2 To better understand the VBD, compare it to a basketball. The ball has low density compared to water. As you push it under the water, the very buoyant ball wants to return to the water surface, where it more closely matches the density of the surrounding air. However, if the ball is deflated (its density is increased), the less buoyant ball can more easily be pushed underwater and may even sink. In the same way, if the density of a Sea Glider is low, it will tend to float at or near the surface. As the density increases, the Sea Glider will begin to sink. It is the VBD which allows this change is density. Figure 2: Sea Glider construction Notice oval-shaped Variable Buoyancy Device near the tail section. Sea Glider Design As mentioned earlier, one of the primary considerations in Sea Glider design is mission duration. Most Sea Glider missions involve data collection over wide expanses of ocean. Moving steadily at ¼ knot/hr, the Sea Glider may need two months to collect data over a 1000 nautical mile mission path. Electrical power must be conserved to ensure full glider operation is maintained over such an extended mission. Effective use of sleep modes, power savings modes and low power peripherals are imperative to minimize power consumption during different operating states encountered during a mission. The current incarnation of the Sea Glider does an excellent job conserving power for its longer mission times. However, it is based on a TT8 68332 32-bit microcontroller. The TT8 runs picoDos as a native operating system. PicoDos is not a true multithreaded operating system. Hence, simultaneous tasks can not be handled at once. As Sea Glider users begin requesting improved autonomous navigation and decision making capabilities, a non-multithreaded architecture will hinder further performance enhancements. To improve Sea Glider performance, autonomous decision making will need to be improved. During navigation, independent decisions about the surrounding ocean state will help make better use of currents, up-welling and down-welling effects. Onboard processing of acoustic data will allow small uploads of significant environmental data when surfacing. Since processor intensive operations take a significant amount of time, a multi-threaded architecture is useful to perform multiple operations at once. Also, if an operation must be performed in a limited span of time, processor performance should 3 have the ability to step up and quickly produce results. With these requirements in mind, the Sea Glider began evaluating a replacement for its embedded TT8 microcontroller. The embedded processor market is diverse, with manufacturers such as MicroChip, Atmel, Phillips, TI, Freescale and Marvell. Ultimately, three microprocessors were evaluated the BlackFin, XScale, ARM9. The ARM9 was selected because it was the only one of the three with an onboard Memory Management Unit (MMU). The LPC3180 is also designed with a 1.2V core voltage and can support 0.9V core voltages as long as the MCU is running at a speed of less than 13MHz. The MMU creates an interface between the physical memory and the microprocessor core. The microprocessor can then address virtual memory, which the MMU will interpret into physical memory locations. The advantages of this architecture include better physical memory organization and utilization, and a simple memory map from the processor standpoint. The disadvantages of an MMU relate to reduced die space for other functions or peripherals and slower absolute memory access speed, at least on the basis of a single word memory access operation. However, the main advantage,for our purposes, of an MMU is that it is able to run a full distribution of Linux. Without an MMU, only uCLinux (an abbreviation for microcontrollerLinux) is available. uCLinux does not require an MMU to run, but therefore, needs special attention to run multiple applications simultaneously. Since the Sea Glider program intends to take advantage of (and contribute to) the full range of the Open Source community’s software the operating system needs to be fully compatible with the standard Linux code base. The decision to run Linux narrowed our selection to the ARM9 based Phillips (now NXP Semiconductor) LPC3180. Phytec, a local embedded system development kit supplier, provided the PHYCore LPC3180 Development Kit. The Phytec development kit consists of a Single Board Computer (SBC) and a carrier board. The SBC is populated with the LPC3180, a 32MB NAND Flash Memory and a 32MB SDRAM Memory. There are also two RS-232 transceivers, three of UARTs are connected through these transceivers. The carrier board supports two RS-232 Serial connections, SD Card, USB, LEDs, a potentiometer for the A/D and user definable switches. The SBC is connected carrier board through a pair of 100-pin connectors that carry LPC3180 signals to the carrier board peripherals and on to an expansion board. Project Overview The full design of the next generation embedded system for the Sea Glider will encompass four phases. 1. Confirm LPC3180 system performance, develop a stable Linux OS and user applications 2. Interface existing sensors and communications hardware with the LPC3180 system 3. Characterize system performance 4. Install the system in the current Sea Glider and test at sea 4 Before starting design, we have attempted to consider possible design roadblocks, but it is possible there may be problems encountered during development. Should this be the case, we may be required to fall back to a previous phase to rectify the issue. Once the previous phase has been corrected, it is important to test all the previous deliverables, to ensure no other system function was mistakenly compromised after the targeted design change. In the limited time of this project, we will address the first development phase: confirm LPC3180 system performance, develop a stable Linux OS and design the user applications 1. Linux installation and basic memory card interface 2. Serial setup 3. Power mode switching 4. Power characterization of above modes and peripherals Linux installation To begin running tests and applications on the LPC3180, an image of the Linux OS and the Linux FileSystem is downloaded via a JTAG interface, into the NAND flash. A bootloader (UBoot) is also loaded into Flash. A secondary bootloader (SIBL) is used to transfer the UBoot and Linux Image and Linux Filesystem into SDRAM where UBoot then boots up Linux. Initially, this caused issues because Linux would boot up successfully, but would constantly refresh making terminal input difficult. Luckily, we had a second LPC3180 available with the same UBoot and Linux Images copied into the Flash, the second system worked and reliably booted Linux. Serial Port testing Serial interfaces are the primary method of communications in ocean going embedded systems, including those aboard the Sea Glider. The simplicity in board layout with a serial communications device combined with easier debug is important in a field where power savings, simplicity and reliability dominate the list of design criteria. Frequently, ocean going systems may need field repair and diagnostic analysis. Serial communications can be quickly probed with an oscilloscope or logic analyzer to get an idea of device operation. Where possible, we will layout boards with serial communication break-out pads to be used as test points. The LPC3180 has seven UARTS. Three UARTS are capable of 921kbps with the remainder at 460kbps. The terminal communications use a standard UART. The auxiliary RS232 port is connected to a high 5 speed UART, which has the same range of frequencies as the regular UARTs, with one extra frequency at 921kbps. We interfaced this second RS232 jack with another terminal window. With the serial port, we simply wished to perform a serial data transfer. To start, we investigated the file system. The /dev directory displays all available devices. If the user wishes to access a device listed under /dev they reference the file by name through the kernel’s open command. This command returns a file descriptor. The file descriptor is a handle with properties and methods which may be used to access the under lying device. The newser.c file at the end of this report shows examples of operations using file descriptors and kernel commands to execute a serial data transfer. On our system, before we get to the results from the file transfer, a little background on Linux devices should be discussed. When checking out the dev file, the user can enter the ls –l command on a file such as /dev/ttyPSHS0. The result will show a major and minor number in this form: 274 1. The number 274 indicates the location of the driver in the kernel code and the minor number indicates the driver instance. All drivers of the same device type will have the same major number, as they all use the same driver code, but will have different minor number, to differentiate them by instance. A USB driver, an Ethernet driver and a serial driver will each have a different major number. Their minor numbers will typically start with zero and increment up for each instance of the driver. The device drivers should be installed as modules. The module can be compiled in the Linux source tree, and added to the system using the command insmod. However, our Linux image had no modules. The Linux Image supplied with the phyCORE system was a monolithic image and couldn’t be tailored using commands such as insmod /rmmod, which add/remove modules. In this case, we rely on the drivers embedded in the development kit to work as is. If they don’t operate correctly, or have all the functionality we need, a time consuming make on a large part of the kernel may be required to make changes. Assuming the installed Linux image has all the drivers available, the user must figure out which device files will actually write to a physical serial port. There could be a dozen different devices files, so knowing which one to use can quickly be determined through a process of trial and error, usually starting with the file with the lowest number, like tty0, or ttyS0. In our case, we found our available serial port was ttyPSHS0. However, we didn’t know this information immediately, and it took some experimentation to figure this out. There will be more on serial port setup later in this paper. As mentioned earlier, the newser.c serial transfer program is used to transmit a string of integers to the host system. This serial code will open the selected driver and the driver will handle the setup of the serial port. A dedicated investigation checked a number of system processes to see if a serial interrupt was being generated with each call of the serial program. Activity was present on the interrupt counters, IRQ addresses and registers, which can be found in the following files: /proc/tty/driver/serial 6 /proc/tty/driver/ttyPSHS /proc/interrupts One important thing to note is that if a serial program doesn’t appear to be working properly (there’s no output on the serial line) with a given driver, every check should be made to ensure that the rest of the system is set up properly. In the case of our development system, a serial port didn’t appear to be working correctly via a probe of the TX pin with the oscilloscope. At this point we began checking to see if the output could internally loopback to the input, so we could check the receive register. This functionality was enabled via the loopback bit in register 0x40054008, the serial port loopback setup register. The serial port schematic indicated that if the loopback bit were enabled, the output TX would loopback to the RX register, while still continuing to propagate onto the TX pin to the RS232 level shifters and physical serial connector. Figure 3. Serial block diagram There is a multiplexer where the node indicates a simple wire connection After continuing to experiment for a handful of days with different serial ports, physical port configurations, C code changes, and internal register modifications to no avail, I demonstrated the problem to my advisor. Up to this point, I had found that the loopback mode disabled output on the serial port. By turning off the loopback mode, the serial port began to function correctly and produce output data. Also, I had found that setting the ‘No Connect’ serial port enable bit would actually enable serial port output. When that bit was cleared, the serial port could not transmit. In my demonstration, I highlighted these findings, but I did it in a newer incarnation of my code, where I ran the correct driver /dev/ttyPSHS0. I set up the oscilloscope on the expansion board where the TX pin was represented and executed the serial binary. To my surprise, the serial port actually worked. The new driver was used, 7 and apparently, had corrected the port enable register despite the improper documentation in the datasheet. Early on, in my serial port debug, I believe I had not originally set up my oscilloscope correctly and used a /dev/ttyS0, and therefore couldn’t see the serial port operating in the first place. Those were the two main variables in not having correct operation. However, during the debug process, I introduced a lot of additional parameters to the problem, which turned out to complicate the process. Of course, this process was an excellent learning experience, no nothing was lost. After finding the serial port working correctly, we wrote a simple Python program to receive the serial data at the host end to verify correct operation. The Python received the LPC3180 data correctly. SD Card The SD Card is important to the development effort. We store executable binaries from the host system onto an SD Card, remove the card from the Host system, and insert it into a slot on the LPC3180 carrier board. The Linux kernel installed on the LPC3180 system has an SD Card driver. The mount command allows access to the SD Card anywhere in the directory tree that we choose to the place the SD Card. However, it is important to umount the SD Card directory before removing it from either the host system or the LPC3180 carrier board. Failure to do so may result in a corrupted superblock on the SD Card. This may be because the latest flash configuration was not properly written to the superblock prior to shutdown. If this happens, an e2fsck command can reassign a secondary, backup superblock to remount the drive. Aside, from when e2fsck is called on the command line, it will also run automatically, after a certain number of flash card insertions. An inexperienced user may be confused by some of the e2fsck messages. While an e2fsck should be periodically run to clean up bad flash memory blocks, its frequency of execution could be reduced on a development system where the number of insertions could be 50-100 a day. Using command line options with tune2fs, the user may select the number of insertions before the e2fsck command issues. Also, there can be some confusion between ext2 and ext3 file systems when the user invokes the fdisk command to format a new flash memory device. Typically, it is ok to use an ext3 file system. The only difference between ext3 and ext2 is the inclusion of journaling in ext3. Once the SD Card flash drive has mounted and can be accessed, it may be automatically mounted on boot-up. A simple way to change the auto mount is to modify the last boot up file. The boot files are usually numbered sequentially. Check the /etc/rcS.d or /etc/init.d directory. In our case, we have an S90check_sd.sh script where the automatic mounting can take place. You can program in automatic mounting by simply placing a mount command with the correct driver and mount directory in the shell script. Other things we may optionally mount in this file are USB devices and other NAND flash devices. 8 Sleep Mode The Sea Glider spends at least 75% of its time in sleep mode, as shown in the timing summary in Figure 6. However, it may need to wake up suddenly, perhaps in response to underwater current induced heading changes or communication requests from an acoustic modem. The LPC3180 is ideally suited to this task, as it comes out of sleep in less than one second, via a low power real time clock running at 32KHz. This real time clock is the only on-chip current draw while the LPC3180 is sleeping. Another possible current draw is the 48MHz USB module, but it would, most likely, be disabled in our final system configuration. Another system current draw is the SDRAM. During sleep mode, the SDRAM is placed in an I/O disabled self-refresh mode. SDRAM self-refresh mode, allows the LPC3180 to wake up with the same memory state it had right before shutdown, without having to perform a time consuming state-saving operation on a large, on-board non-volatile memory. The issue first encountered with the sleep mode was that terminal communications would cease after placing the SDRAM in self-refresh mode. This was because terminal communications relied on reads and writes to the SDRAM. Once the communications terminal was shut off, the final sleep mode command could not be entered. The solution to this problem was to create a compiled C binary to issue all the commands in series. With the binary loaded into the LPC3180 cache, the self-refresh would have no effect on the continued execution of commands, until the final sleep mode command. Wake-up begins with a Start Interrupt. On our test system, the start interrupt will be generated by the RTC clock. However, it may also be generated by other external interrupts such as serial pins, timers capture inputs, USB or SD card insertion among others. We could successfully wake up after an interrupt from the real time clock. After waking up, the system state was preserved in the SDRAM, and Linux was immediately available. We confirmed this operation by running binaries from the command line on the next command after startup. Power Characterization We tested power by replacing the main Vcc jumper with two leads, to which we could connect the current meter contacts. The preferred method to determine this current would have been to use a small .05 or .025 Ohm shunt, whereby we could measure the voltage across the shunt. However, the required shunt was in the 0805 package profile, and an example of such a small shunt was difficult to find in the final days of the project. Power characterization on this part was complicated by the interaction between our main Vcc test point, the SBC and the other peripherals on the carrier board. However, compared to other available test points, the Vcc input was our most trustworthy option. Other current test points were available; specifically four jumpers that were located physically close to the LPC3180. These jumpers represented Vdd and Vdd IO supplies on the chip. Since Vdd supplies are 9 the only power supply pins on the LPC3180, it seemed logical that only jumper supplied Vdd should be applied to these pins. However, figure 5 includes a block diagram showing a Vcc input into the chip. Without understanding every termination point for this Vcc input, we could not rely on the Vdd test Figure 5, Block diagram of LPC3180 mounted on Phytec SBC, interfaced with phyCORE carrier board. points for our current consumption numbers. However, a quick look at the sum total of the currents passing through the Vdd jumpers was approximately 20mA at 1.2V @ 13MHz. As we will see shortly, it is far lower than the power being consumed through the Vcc jumper at a similar performance setting. This finding holds hope that a properly designed board will yield a very lower power device. Our final power characterization, detailed in Figure 6 below, relies on placing the chip into a power saving mode, and then disabling a number of carrier board elements. In regular operation after reset, at 208MHz, a 3V supply provides most of the system power and draws 130mA. This is high compared to the estimates in the LPC3180 datasheet (80mA @ 1.2V), and it is obvious that the other board electronics are sinking a significant quantity of current. By dropping the chip from 1.2V to 0.9V on the core and using the minimum frequency of 13MHz (this configuration is called Direct Mode), we bring the current consumption to 47.8mA at 3V. The Direct Mode spec into the device core is 7mA typical at 0.9V, 10 excluding currents to drive the I/O circuitry. Some obvious contributors to the 47.8mA are 4 x 6mA LEDs. After removing the LEDs, the current drops by 23mA. Further reductions are realized by turning off the USB PLL, disconnecting all serial cables and removing the SD Card from its slot. Current reduction work will continue in the upcoming weeks, as we begin to determine the power consumption of each peripheral device. SLEEP DISK ACCESS (WRT) ACTIVE SAMPLE IDLE COMPUTATION (KALMAN) TT8 (mA @ 10V) 2.19 45.8 19.8 39.8 19.8 81.8 LPC3180 (mA @ 3V) 13.1 ~19.5 19.4 (9.6k) est 19.7(115k) 17.9 TIME (SECONDS) 22771.996 755.016 1687.776 3066.738 967.334 33.378 Figure 6, Summary of currents during an average dive (simulated average dive for LPC3180 data, using the code ion the appendix) Time could be considered to represent a percentage of time, where it is obvious the glider is spending most of its time in sleep. At the time of this report, sufficient data during sampling and processor intensive computations was not yet available. Conclusion The results are very promising, as active computation uses about 1/3 the power (same current and about 1/3 of the voltage) of the active computation on the legacy TT8. The sleep power consumption number is about twice as high on the LPC3180 compared to the TT8. We hope this can be reduced as we account for the external draws on the LPC3180 power supply. Disk access is quite a bit lower, as LPC3180 running at lowest speed, has plenty of bandwidth to handle the Linux access to an external memory card, while the TT8 is running at full speed to accomplish the same objective. We also hope that the reduce power of the idle and active modes, compared to the TT8 can be taken advantage of, allowing the sea glider to actively compute during a greater portion of its mission. The intelligence gained from active computation may lead to richer more data rich missions. Finally, the results of the Sea Glider power measurements are relevant to the processor only. They don’t consider the effect of sensing , control and communications electronics. Continued optimization of the power requirements from these systems could have large gains in electrical performance. 11 Final Thoughts Going forward, the main tasks for this part of the Sea Glider project will involve a better understanding of the external circuitry which is drawing power on the SBC and also on the carrier board. The next task will be development of a functional SPI bus, as many of the existing Sea Glider systems rely on this bus. Then we will begin interfacing these functions with the existing Sea Glider hardware. 12 References Phytec phyCORE-LPC3180 Hardware Manual, April 2007, L-681e-2.pdf Phillips LPC3180 Preliminary Datasheet, February 21, 2006, Rev 0.1, lpc3180_DS-1.pdf Phillips UM10198 LPC3180 User Manual , June 6, 2006, Rev 01, UM10198_1.pdf ARM926EJ-S Development Chip Reference Manual, 2006, DD10287B_arm926ejs_dev_chip_technical_reference_manual.pdf Micron Mobile SDRAM datasheet, 2005, MT48H32M16LFm.pdf Analog Devices Port Transceivers Datasheet, 2006, ADM3307E_3310E_3311E_3312E_3315E.pdf 13 Code Appendix /* autoslp.c: Sleep code */ #include #include #include #include #include #include #include #include #include #include #include #include #include <stdio.h> <stdlib.h> <unistd.h> <string.h> <errno.h> <signal.h> <fcntl.h> <ctype.h> <termios.h> <sys/types.h> <sys/mman.h> <linux/gpio.h> <sys/ioctl.h> #define FATAL do { fprintf(stderr, "Error at line %d, file %s (%d) [%s]\n", \ __LINE__, __FILE__, errno, strerror(errno)); exit(1); } while(0) #define MAP_SIZE 4096UL #define MAP_MASK (MAP_SIZE - 1) unsigned long write_mem(off_t target, unsigned long writeval); unsigned long read_mem(off_t target); int led_off(void); int main(int argc, char **argv) { unsigned long read_result; int always_zero; if(argc > 1) { fprintf(stderr, "\nUsage:\t%s\n", argv[0]); exit(1); } // always_zero = led_off(); read_result=write_mem(0x40004044, 0x0); // Direct RUN mode in PWR CTRL read_result=write_mem(0x40004050, 0x142); // Enable 13' Clk (from PLL397) do{ read_result=read_mem(0x40004050); // wait for 13' to stabilize }while (read_result!=0x143); read_result=write_mem(0x40004020, 0x1000000); // enable rtc interrupt to main processor read_result=write_mem(0x4000402C, 0x1000000); // rising edge of start signal read_result=write_mem(0x40004024, 0x1000000); // clear the interrupt // read_result=write_mem(0x40004030, 0x1000000); // pin int start up is probably unnecessary read_result=write_mem(0x40024010, 0x10); // reset rtc read_result=write_mem(0x40024010, 0x00); // reset rtc read_result=write_mem(0x40024008, 0xA); // set rtc timer to 10 seconds read_result=write_mem(0x40024010, 0x1); // enable rtc interrupt from rtc module read_result=write_mem(0x40004044, 0x280); // auto exit SDRAM self refresh enable and self refresh request read_result=write_mem(0x40004044, 0x380); // self refresh request read_result=write_mem(0x40004044, 0x80); // self refresh request read_result=write_mem(0x40004044, 0x81); // enter STOP mode // sleep read_result=write_mem(0x40004044, 0x0); // exit STOP mode and make sure Direct RUN is started read_result=write_mem(0x40024008, 0x0); // return match register to 0 seconds read_result=write_mem(0x40024014, 0x1); // clear match interrupt status read_result=write_mem(0x40024010, 0x0); // clear match interrupt status read_result=write_mem(0x40004020, 0x0000000); // disable rtc interrupt to main processor read_result=write_mem(0x40004024, 0x0000000); // clear the interrupt 14 read_result=write_mem(0x40004044, 0x62); // exit STOP mode and make sure Direct RUN is started return(0); } unsigned long write_mem(off_t target, unsigned long writeval) { unsigned long read_result; int fd; void *map_base, *virt_addr; if((fd = open("/dev/mem", O_RDWR | O_SYNC)) == -1) FATAL; fflush(stdout); /* Map one page */ map_base = mmap(0, MAP_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, target & ~MAP_MASK); if(map_base == (void *) -1) FATAL; fflush(stdout); virt_addr = map_base + (target & MAP_MASK); read_result = *((unsigned long *) virt_addr); printf("Value at address 0x%X (%p): 0x%X\n", target, virt_addr, read_result); fflush(stdout); *((unsigned long *) virt_addr) = writeval; read_result = *((unsigned long *) virt_addr); printf("Written 0x%X; readback 0x%X\n", writeval, read_result); fflush(stdout); if(munmap(map_base, MAP_SIZE) == -1) FATAL; close(fd); return read_result; } unsigned long read_mem(off_t target) { unsigned long read_result; int fd; void *map_base, *virt_addr; if((fd = open("/dev/mem", O_RDWR | O_SYNC)) == -1) FATAL; fflush(stdout); /* Map one page */ map_base = mmap(0, MAP_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, target & ~MAP_MASK); if(map_base == (void *) -1) FATAL; fflush(stdout); virt_addr = map_base + (target & MAP_MASK); read_result = *((unsigned long *) virt_addr); printf("Value at address 0x%X (%p): 0x%X\n", target, virt_addr, read_result); fflush(stdout); if(munmap(map_base, MAP_SIZE) == -1) FATAL; close(fd); return read_result; } int led_off(void) { /* int f_gpio; int j; struct gpio_control leds[4]; */ 15 unsigned long dummy; printf("Turning LEDs off\n"); dummy=write_mem(0x40028008, 0x8C); /* leds[0].Pin leds[1].Pin leds[2].Pin leds[3].Pin = = = = GPO_02; GPO_03; GPO_07; GPO_06; // // // // // clear GPO LED bits LED1 LED2 LED3 LED4 f_gpio = open("/dev/gpio",1); for (j = 0; j < 4; j++) { leds[j].Arg = 0; ioctl(f_gpio,GPIO_IOCSPIN,&leds[j]); sleep(2); } close(f_gpio); printf("LEDs off\n"); */ return 0; } /* serial communications code */ #include #include #include #include #include #include #include #include #include #include #include <stdio.h> <termio.h> <string.h> <stdarg.h> <stdlib.h> <unistd.h> <fcntl.h> <math.h> <sys/time.h> <ctype.h> <errno.h> int ConnectSerial(char *portname, int baud, char parity, char databits, char stopbits, char flowcontrol) { int fd; struct termios options; int baudflag; fd = open(portname, O_RDWR | O_NDELAY | O_NOCTTY); if (fd == -1) { return -1; } tcgetattr(fd, &options); switch(baud) case 110: case 300: case 600: case 1200: case 2400: case 4800: case 9600: case 19200: case 38400: { baudflag baudflag baudflag baudflag baudflag baudflag baudflag baudflag baudflag = = = = = = = = = B110; break; B300; break; B600; break; B1200; break; B2400; break; B4800; break; B9600; break; B19200; break; B38400; break; 16 case 57600: baudflag = B57600; break; case 115200: baudflag = B115200; break; case 230400: baudflag = B230400; break; case 460800: baudflag = B460800; break; case 921600: baudflag = B921600; break; default: baudflag = B9600; printf("Baud rate entered is not available\n"); printf("Default will now be 9600bps\n"); break; } cfsetispeed(&options, baudflag); cfsetospeed(&options, baudflag); options.c_cflag options.c_lflag options.c_oflag options.c_iflag |= &= &= &= (CLOCAL | CREAD); ~(ICANON | ECHO | ECHOE | ISIG); ~OPOST; ~(INLCR | IGNCR | ICRNL); switch(parity) { case 'e': case 'E': options.c_cflag options.c_cflag options.c_iflag break; case 'o': case 'O': options.c_cflag options.c_cflag options.c_iflag break; default: options.c_cflag options.c_cflag options.c_iflag break; } |= PARENB; &= ~PARODD; |= (INPCK | ISTRIP); |= PARENB; |= PARODD; |= (INPCK | ISTRIP); &= ~PARENB; &= ~PARODD; &= ~(INPCK | ISTRIP); switch(stopbits) { case 2: options.c_cflag |= CSTOPB; break; default: options.c_cflag &= ~CSTOPB; break; } switch(databits) { case 7: options.c_cflag options.c_cflag break; default: options.c_cflag options.c_cflag break; } switch(flowcontrol) case 1: options.c_iflag options.c_cflag break; case 2: options.c_iflag options.c_cflag break; &= ~CSIZE; |= CS7; &= ~CSIZE; |= CS8; { |= (IXON | IXOFF | IXANY); &= ~CRTSCTS; &= ~(IXON | IXOFF | IXANY); |= CRTSCTS; 17 default: options.c_iflag &= ~(IXON | IXOFF | IXANY); options.c_cflag &= ~CRTSCTS; } tcsetattr(fd, TCSANOW, &options); return fd; } int main(int argc, char *argv[]) { int port_fd; int bit, n; int cmd; char buff [80]; int len, ret; int baud; printf("Pick a baud rate between 110 and 115200\n"); scanf("%d", &baud); if ((port_fd = ConnectSerial(argv[1], baud, 'N', 8, 1, 0)) == -1) { perror("Could not open serial port"); fprintf(stderr, "(%d)\n", errno); return 1; } for(n = 0; n < 63; n++) { sprintf(buff, "This serial port is working just fine, for the %dth time.\n", n+1); len = strlen(buff); ret = write(port_fd, buff, len); if(len != ret) { fprintf(stderr, "Cycle %d Tried to write %d, wrote %d\n", n, len, ret); } } /* bit = TIOCM_DTR; */ /* /* ioctl(port_fd, TIOCMBIC, &bit); */ printf("DTR is off\n"); */ /* /* /* /* while (1) { */ cmd = getchar(); */ if (cmd == 13 || cmd == 10) */ continue; */ /* /* if (cmd != '1' && cmd != '0') */ break; */ /* /* /* /* if (cmd == '1') */ ioctl(port_fd, TIOCMBIS, &bit); */ else if (cmd == '0') */ ioctl(port_fd, TIOCMBIC, &bit); */ /* /* /* n = sprintf(buff, "turning %s\r\n", cmd == '1' ? "on" : "off"); */ Write(port_fd, buff, n); */ } */ close(port_fd); return 0; } # Python serial receive code import serial, sys 18 # removed import serial and import sys #out = serial.Serial(baudrate=115200, timeout=5, port='/dev/ttyUSB0') #inp = serial.Serial(baudrate=115200, timeout=5, port='/dev/ttyUSB1') #test_string = "01234567890123456789012345678901234567890123456789" ser = serial.Serial(baudrate=115200, timeout=5, port='/dev/ttyS1') sys.stdout.write("Starting\n") while(1): sys.stdout.write(ser.read(1)) ser.close() #ser = serial.Serial(baudrate=9600, port='/dev/ttyS1') #print ser.portstr #ser.write("got it") #ser.close() 19