embedded techniques for everyone ; solve atleast one problem of the world a day ; provide the world what you do not get ; invent and service the world
Tuesday, November 03, 2009
System knowledge of an Embedded Engineer
Monday, September 28, 2009
Marvell 88E1111S initialization: How To
Register | Address |
#define MIIM_CONTROL | 0x00 |
#define MIIM_STATUS | 0x01 |
#define MIIM_ANAR | 0x04 |
#define MIIM_GBIT_CONTROL | 0x09 |
The initialization code is as follows:
/* Reset the chip */
write_phy_reg(MIIM_CONTROL, 0x9140);
/* Wait for Reset over */
while(read_phy_reg(MIIM_CONTROL) & 0x8000);
/* Marvel 88E1111S sequence */
write_phy_reg(0x1d, 0x1f);
write_phy_reg(0x1e, 0x200c);
write_phy_reg(0x1d, 0x05);
write_phy_reg(0x1e, 0x0);
write_phy_reg(0x1e, 0x100);
/* Enable the 88e1111 internal RX/TX clock delay */
write_phy_reg(0x14, 0x0cd2);
/* Set the Gigabit control register and
Autonegotiation Advertisement register */
write_phy_reg(MIIM_GBIT_CONTROL, 0xe00);
write_phy_reg(MIIM_ANAR, 0x1e1);
/* Reset Again */
write_phy_reg(MIIM_CONTROL, 0x9140);
/* Check for the link to come up */
while((status = read_phy_reg(MIIM_CONTROL)) & 0x0004);
/* Now, initialization is over. You can parse the status Register to know the Speed and Duplex */
Friday, September 11, 2009
JLPT Level 1 book with english translation
Tuesday, September 08, 2009
Howto create job
MPC8313e eTSEC checksum offloading: Programming guidelines
1) First of all, during initialization, enable IPCSEN and TUCSEN bits of Transmit Control Register (TCTRL). 2) Next, in the buffer pointed by the buffer descriptor, the first 8 bytes must be allocated for the Frame control block (FCB). Fill it by setting the appropriate bits of IP, IP6, TUP, UDP, CIP, CTU and L4OS, L3OS fields. (When filling a normal IP packet subsequent to FCB will have L4OS as 20 and L3OS as 14 respectively.) 3) Fill the packet from the next byte of FCB. 4) Set the Length filed of the buffer descriptor with (Packet data length + 8). (The length of FCB is added to the actual packet data length.) 5) Set TOE bit of the flags field of the Transmit Buffer descriptor and Transmit the packet. 6) Make sure the IP, TCP and UDP checksum fields of your packet data is filled with zero. |
1) First of all, during initialization, enable IPCSEN and TUCSEN and PRSDEP fields of Receive Control Register (RCTRL). 2) The first 8 bytes of the received data is the Frame control block (FCB). First check whether IP, TUP bits are set to make sure the packet has come under IP, IPv6, TCP and UDP category. Then check CIP and CTU whether the checksum has been verified and then the result bits EIP and ETU. (In case of fragmented packets(even they are TCP or UDP), they will not come under TCP, UDP category. Those packets have to be sent to upper layer for checksum verification) 3) Subtract 8 from Received packet length and use the remaining packet. |
For further troubleshooting,
1) Check with the latest errata. For example,
http://www.freescale.com/files/32bit/doc/errata/MPC8313ECE.pdf?fpsp=1&WT_TYPE=Errata&WT_VENDOR=FREESCALE&WT_FILE_FORMAT=pdf&WT_ASSET=Documentation
2) Check the packet structure and data with packet capture software/analyzer.
Sunday, August 30, 2009
Xilinx TEMAC Checksum offload programming sample
In UDP layer, Do not forget to fill Checksum field of UDP header of the packet with zero.
Calculate the Pseudo Checksum and send it to driver.
How to calculate pseudo_csum?
unsigned int pseudo_csum;
unsigned short *iphdr_ptr;
pseudo_csum = *iphdr_ptr ++; /* Source IP Address (First two bytes) */
pseudo_csum += *iphdr_ptr ++; /* Source IP Address (Last two bytes) */
pseudo_csum += *iphdr_ptr ++; /* Destination IP Address (First two bytes) */
pseudo_csum += *iphdr_ptr ++; /* Destination IP Address (Last two bytes) */
pseudo_csum += htons(UDP_PROTOCOL_ID); /* UDP Protocol ID: 0x11 */
pseudo_csum += udp_length; /* UDP Packet Length (Data + Heaader Length) */pseudo_csum = (pseudo_csum & 0xffff) + (pseudo_csum >>16);
pseudo_csum += (pseudo_csum >>16);
return (unsigned short)pseudo_csum;
Step 2:
Set the Transmit buffer descriptor with these extra settings and transmit.
TransmitBD.APP0 = TransmitBD.APP0 | TX_CSCNTRL;
TransmitBD.APP1 = (TX_CSBEGIN << 16) | TX_CSINSERT;
TransmitBD.APP2 = pseudo_csum;
TX_CSCNTRL is 0x01
TX_CSBEGIN is 34 for IPv4/UDP. It is starting of UDP Header (Ethernet Header size (14) + IP Header size (20)).
TX_CSINSERT is 40 for IPv4/UDP. It is Checksum field offset (starting of UDP header(34) + Checksum offset (6)).
For Reception
In reception, the hardware checksum offload engine just adds the IP packet data in 16 bits. So, subtract the IP header, subtract the UDP checksum, calculate and add the pseudo header and verify with the checksum in the packet.
unsigned short *ip_data = (unsigned short *)(RecieveBD.Buffer + 14);
unsigned short *udp_hdr = (struct udp_header *)(RecieveBD.Buffer + 14 + 20);
unsigned short packet_csum, hw_csum;
unsigned int temp;
Take the hardware generated checksum and shift 16 bits left.
temp = RecieveBD.APP3 & 0xffff;
temp = temp << 16;
Subtract the first 12 bytes of IP header (except the Source and Destination IP addresses: pseudo header)
for (i = 0; i < 6; i++) {
temp -= ip_data[i];
}
Add the UDP protocol ID(0x11) (pseudo header).
temp += htos(UDP_PROTOCOL_ID);
Subtract the UDP checksum. And keep it for later validation.
packet_csum = udp_hdr->check_sum;
temp -= packet_csum;
Add the UDP packet length (pseudo header).
temp += udp_hdr->length;
temp = (temp & 0xffff) + (temp >> 16);
temp += (temp >>16);
Compare the result checksum (16 bits)
hw_csum = (unsigned short)temp;
if (hw_csum != 0xffff)
hw_csum = ~hw_csum;
if (hw_csum == packet_csum)
Checksum passed;
else
Checksum failed;
Send the result to upper layer. Just follow the algorithm for TCP and IPv6 too. For optimized solution and pseudo code for checksum verification, read the following post:
http://embeddedknowledge.blogspot.com/2011/07/xilinx-temac-checksum-offload.html
If you have any queries write as comments.
Friday, August 28, 2009
Thursday, August 27, 2009
Checksum error: differs by 1 or 2
For example, the correct checksum is 0x5e94. But, your calculation is 0x5e96. To solve this problem, check whether the carry has been added.
csum += *(unsigned short)data;
:
csum = (csum & 0xffff) + (csum >> 16); /* Please add this carry too */
csum = csum + (csum >> 16); /* If the carry is again generated, it has to be added */
Wednesday, August 26, 2009
Software design and implementation for TCP/UDP/IP Checksum offloading Interface
Supported Layers (TCP/UDP/IP) | Some support only TCP/UDP. Some support IP too. |
Support for packets with Options header | Some controllers do not calculate the checksum for packets with options header. |
Checksum calculation for UDP/TCP Pseudo Header | Most of controllers which do not support IP layer and Options header expects the protocol stack to calculate the UDP/TCP Pseudo header checksum and seed them with. |
Driver Interface specification | Driver interface such as input parameters and output format of the Checksum Offload Engines vary, though mostly interfaced with buffer descriptors. |
Support for fragmented support | Some support fragmented packets and some do not. |
Error packets handling | Whether the hardware rejects the erroneous packets or leaving it to the software also varies. |
VLAN packets support | Some support and some do not support. |
- Configuration
COE supports IP? |
COE supports TCP? |
COE supports UDP? |
COE support is full or partial? |
COE supports fragmented packets? |
- Outbound flow and parameters
Layer3 type = IPv4 or IPv6? | flag |
Layer4 type = TCP or UDP? | flag |
Layer3 calculation by COE? | flag |
Layer4 calculation by COE? | flag |
Should calculate Pseudo header? | flag |
Byte offset for layer4 start | offset |
Checksum offset for layer4 | offset |
Checksum offset for layer3 | offset |
Pseudo Header Checksum | data |
Layer3 type = IPv4 or IPv6? | flag |
Layer4 type = TCP or UDP? | flag |
Layer3 calculation by COE? | flag |
Layer4 calculation by COE? | flag |
Pseudo Header Checksum | data |
UDP
Set UDP Checksum field to 0.IP
IF (COE Supports UDP? is Yes)
{
IF (this is fragmented packet AND COE supports fragmented packet? is False)
{
Calculate by software
}
/* Just send the packet. Let COE calculate the checksum */
Set Layer4 type = UDP;
Set Layer4 calculation by COE? = Yes;
IF (COE support is partial)
{
Pseudo header checksum = Calculate just pseudo checksum
}
}
ELSE
Calculate by software
IF (COE Supports IP? is No)
{
Calculate by software
}
ELSE
{
Set Layer3 type = IP;
Set Layer3 calculation by COE? = Yes;
}
- Inbound flow and parameters
IP
IF (COE Supports IP? is No)
{
Verify by software
}
/* All received are correct packets, when COE is enabled */
UDP
IF (COE Supports IP? is No)
{
Verify by software
}
ELSE IF (packet is fragmented AND COE supports fragmented packet? is False)
{
Verify by software
}
Wednesday, August 19, 2009
Love letter
He never got reply. Because, she had made reckless run with another guy.
How to
Saturday, August 15, 2009
Embedded systems Coding: Issues and techniques - Part 1
Optimization is an unavoidable one to improve the speed and to reduce the size of the code in embedded systems. But, the compiler will have strict eyes on your code and generate more tricky code which may result in unexpected result. Look at the following typical case:
What do you intend to do in the above code? It is a polling where each time it should read the status register and check for the status update by the hardware. But the compiler will think in more smarter way that why to read the SAME memory location each time unnecessarily since the content is going to be the SAME. The compiler will not know that its content is going to be changed by hardware after sometime. So, it is dare enough to generate the assembly code which is equivalent to
which may result in infinite loop in case the IO_COMPLETED flag is not set when the code reads the status register for the first time.
So, what do you have to do? You have to understand that IO mapped memory is different from the real memory and its content is subjected to change internally by hardware without any external CPU write. So, you have to teach the compiler to treat them separately.
Declare the IO memory locations as volatile so that the compiler will not optimize the read/write operations of such volatile memory locations. So, the above code will work perfect with optimization.
Wednesday, July 29, 2009
Famous Embedded Systems exhibitions
- ESEC Embedded Systems Expo, Japan (http://www.esec.jp/en/)
- ET Embedded Technology, Japan (http://www.jasa.or.jp/et/english/index.html)
- ESC Embedded System Conference, India (http://esc-india.com/index.html)
"Embedded system" in different languages
Tamil பதிகணினியியல் Padhi kaniniyiyal
Japanese 組み込みシステム(くみこみシステム) Kumikomi shisuthemu
Chinese 嵌入式系统 Kan Ru Shi Si Ton
Korean 임베디드 시스템
Friday, July 24, 2009
Dos and Donts in Embedded system design
I remember when I was new to embedded, I was designing a USB device firmware in Linux. It is for transferring the data from the host and to store it in the storage disk of the target. What I did was, in the interrupt service routine of the USB firmware, I read the block of data from the USB device endpoint and also called the system call to store it in the storage disk. Of course, it was working. But, what happened you know? The whole Linux system except my firmware stopped working, when a file is transferred to the target. Hope you know the problem. Later, the code was corrected as follows: the USB firmware which is running in the kernel level is added with system calls to communicate with user level application. A separate user application task was created which will call the system call to get the block of data from the USB firmware and to call another system call to write the data in the storage disk. This was working fine with all other tasks also getting scheduled whenever there is a gap when the USB firmware and the storage disk driver has to wait for the hardware response.
Though I knew what is Interrupt Service routine and what is System call, I did not know what will happen if I put it there. So, at first, let me give you some do's and don'ts when designing a system.
- Do not waste the CPU cycles in busy waiting as follows:
In the above example, the driver writes an IO command to device and wait for the device to complete it. Instead, you can go to sleep so that other tasks can utilize the CPU and the device will interrupt you when the intended job is completed.
Let me modify the code as follows:
- Do not call blocking calls from contexts where scheduling is forbidden
Blocking calls are the function calls which may cause the calling entity to sleep. There are some contexts which may run with higher priority than the scheduler and the scheduler is forbidden like Interrupt Handler, critical sections, higher priority kernel threads. Calling blocking calls from such contexts may result in unwanted results like deadlocks. It will keep other tasks in waiting unnecessarily. For example, look at the following code. First of all, whether a particular OS will allow such sleep from Interrupt context is a main question. Even if it allows, sleeping in interrupt service routine will stop all lower priority interrupts, will stop the whole scheduling since because Interrupt service routine is a highest priority context. So, the whole system will sleep during that delay.
- Do not do your own processing in callbacks
- Do not use local variables in very large size
In most of systems, each Task is allocated specified and limited size stack space. Since, the local variables consume memory from the stack, the stack memory may not become enough and further it will lead to stack overflow and system crash. So, know the limit and use. In the above example, if the calling task is allocated 300 bytes of stack, what will happen? This function itself uses more than 256 bytes. The task context also might be saved in the stack space. So, it may cause overlap and cause damage. Instead, it is better to allocate the buffer from heap or memory pools dynamically and use. Or, you can allocate from Global memory if mutual exclusion is not a major problem.
- Do not keep Global resources un-protected
Whenever you are adding a global variable or global buffer memory or global structure, the first thing you have to worry about it is mutual exclusion. Is it getting shared between more than one task? When it is accessed by one context, is it possible to getting pre-empted with another context? If so, it has to be protected with mutual exclusion. When the variable is shared between interrupt service routine and Task, before accessing the variable from the Task, the interrupt has to be disabled. Since the Interrupt service routine is mutually exclusive in nature, no need protect the globals inside the interrupt service routine. When the variable is shared between Tasks, you should use OS primitives for mutual exclusion.
- Avoid use of the user system calls in driver or kernel mode
Most of Operating systems have separation between user and kernel applications. Though mutual exclusion might be needed in user applications and drivers, it is not good to use the user primitives in driver. Instead, it will have the equivalent for kernel mode. So, use that.
Good luck!