Archive for the ‘C’ Category

Simple Minix 3 driver

Friday, December 25th, 2009

I have made a simple driver for Minix 3 (Tested on Minix 3.1.4, should work on 3.1.5).
This driver controls the caps lock led by writing: write a 0 to /dev/capslockled to turn it off and a 1 to turn it on. Note: this driver is not thread safe as it might interfere with the TTY driver.

The driver can be downloaded here.

The danger of typo’s in a switch statement in C

Tuesday, December 1st, 2009

A typo in a case label or default label inside a switch statement can result into normal labels without the compiler complaining. This can introduce serious and hard to find bugs. This will happen in the following two situations:

1. The space in case<space><number>: is forgotten.
2. Any typo in the default: label.

Consider the following code:

/* A typo in the case labels or default label in a switch statement
 * can result into a normal label in the following situations:
 *  
 * 1. The space in case<space><number>: is forgotten.
 * 2. Any typo in the default: label.
 *  
 * What mostly happens is that the statements under the wrongly typed case label
 * will be part of statements under the case label above. These statements
 * usually end with the break statement and thus the statements under the wrongly
 * typed case label will never be executed.
 * 
 * Author: Bianco Zandbergen, november 2009      
 */  
#include <stdio.h>
 
int main(void)
{
    int i = 0;
    int t1 = 0;
    int t2 = 0;
 
    switch(i) {
        case 1:
            printf("Case 1\n");
            break;
        case2: /* A typo in 'case 2:' results into a normal label */
            printf("case2\n");
            break;
        defaultt: /* A typo in 'default:' results into a normal label */
            printf("defaultt\n");
    }
 
    /* lets test if we can jump to these labels */
    if (t1 == 0) {
        t1++; /* avoid looping */
        goto case2;
    }
 
    if (t2 == 0) {
        t2++; /* avoid looping */
        goto defaultt;
    }
 
    return 0;
}

While it is correct that the compiler does not complain (a label can be put anywhere), i think it would be wise if the compiler generates a warning when using the default options.

Output of gcc 4.3.4 on GNU/Linux with the code above:

bianco@box ~/temp/label $ gcc -o label label.c
bianco@box ~/temp/label $

Output of Borland C++ compiler 5.5.1 on Windows with the code above:

C:\dev\C\labels>bcc32 label.c
Borland C++ 5.5.1 for Win32 Copyright (c) 1993, 2000 Borland
label.c:
Turbo Incremental Link 5.00 Copyright (c) 1997, 2000 Borland
C:\dev\C\labels>

Binary macro for C

Thursday, August 21st, 2008

Found a usefull macro to use binary numbers in C:

#define B8__(x) ((x & 0x0000000FLU) ?   1 : 0) \
              + ((x & 0x000000F0LU) ?   2 : 0) \
              + ((x & 0x00000F00LU) ?   4 : 0) \
              + ((x & 0x0000F000LU) ?   8 : 0) \
              + ((x & 0x000F0000LU) ?  16 : 0) \
              + ((x & 0x00F00000LU) ?  32 : 0) \
              + ((x & 0x0F000000LU) ?  64 : 0) \
              + ((x & 0xF0000000LU) ? 128 : 0)
 
#define B8(d) ((unsigned char) B8__(HEX__(d)))
 
// use it
B8(10101010)

Blackfin BF533: Core and System clock

Tuesday, February 5th, 2008
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
void init_PLL(void)
{
	short tmp;
 
	*pSIC_IWR=0x01; // only PLL wakeup
	ssync();
 
	*pPLL_DIV = 0x001B; //cclk=vco/1;sclk=vco/11
	ssync();
 
	tmp = cli();
 
	*pPLL_CTL=(12<<9); //vco=12*clkin, clkin=27M
	ssync();
 
	idle();
	sti(tmp);
}

Blackfin BF533: Programmable flags with interrupts example

Tuesday, February 5th, 2008
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
/*
	This example shows how to use 
	interrupts with programmable flags.
	PF8 will be used. When PF8 goes from low to high
	there will be an interrupt.	
*/
 
#include<stdio.h>
#include<cdefbf533.h>
#include<sys\exception.h> // needed for interrupts
 
// prototype
EX_INTERRUPT_HANDLER(FlagA_ISR);
 
void main(void)
{
 
	// Register FlagA ISR to interrupt vector group 12
	register_handler(ik_ivg12, FlagA_ISR);
 
	// set direction of programmable flag PF8 to input
	*pFIO_DIR &= ~PF8;
	ssync();
 
	// interrupt enable PF8
	*pFIO_INEN |= PF8;
	ssync();	
 
	// give interrupt when FIO_FLAG_D PF8 changes
	*pFIO_MASKA_D |= PF8;
	ssync();
 
 
	// Bind FlagA interrupt to IVG12
	*pSIC_IAR2 |= 0x00005000; // flag A IVG12
	ssync();
 
 
	// Enable PFA in system interrupt mask register
	*pSIC_IMASK = 0x00080000;
	ssync();
 
	// enable IVG12 in core interrupt mask register
	*pIMASK |= 0x00001000;
	ssync();
 
	// wait for interrupt
	while(1);
}
 
EX_INTERRUPT_HANDLER(FlagA_ISR)
{	
	printf("\n interrupt received!");
	fflush(stdout);
 
	// or do something else...
}

Blackfin BF533: Programmable Flags example

Tuesday, February 5th, 2008

There are 5 important registers for the Programmable Flags:

FIO_DIR: I/O direction
FIO_FLAG_D: Direct access to data of the programmable flags
FIO_FLAG_S: Write 1 to set flags
FIO_FLAG_C: Write 1 to clear flags
FIO_FLAG_T: Write 1 to toggle flags

With the last three registers it is not needed anymore use bitwise functions for setting, clearing and toggling flags :)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
/*
	This example shows how to use programmable flags of the BF533.
	The BF533 has 16 programmable flags (GPIO).
	This program toggles all flags.	
*/
 
#include <cdefBF533.h>
 
int main(void)
{
 
	int delay;
 
	// set direction of all flags to output
	*pFIO_DIR = 0xFFFF;
	ssync();
 
	// directly access data register
	// set all flags to high
	*pFIO_FLAG_D = 0xFFFF;
	ssync();	
 
	while (1) {
 
		// set all flags to high
		*pFIO_FLAG_S = 0xFFFF;
		ssync();
 
		for (delay = 0x00FFFFFF; delay>0; delay--); 
 
		// clear all flags (set to low)
		*pFIO_FLAG_C = 0xFFFF;
		ssync();
 
		for (delay = 0x00FFFFFF; delay>0; delay--);
 
		// FIO_FLAG_T register can also be used to toggle here!		
	}	
 
	// never reached
	//return 0;
}

Blackfin BF533: ADSP-BF533 EZKIT LITE LED’s example

Tuesday, February 5th, 2008
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
/*
	This example shows how to use the 6 LED's 
	on the ADSP-BF533 EZ-KIT LITE.
	The LED's are connected on the Flash A chip instead of GPIO.
	This program will toggle the LED's
*/
 
 
#include <cdefBF533.h>
#include <stdio.h>
 
// addresses in Flash for the LED's
#define pFlashA_PortB_Dir	(volatile unsigned char *)0x20270007
#define pFlashA_PortB_Data	(volatile unsigned char *)0x20270005
 
int main(void)
{
 
	printf("Showing how the leds work on the BF533 EZ-KIT Lite");
	fflush(stdout);
 
	// External Bus Interface Unit setup, for access to flash A
	// It is not important to understand this
	*pEBIU_AMBCTL0	= 0x7bb07bb0;
	*pEBIU_AMBCTL1	= 0x7bb07bb0;
	*pEBIU_AMGCTL	= 0x000f;
 
	// flash data direction, b 111111
	*pFlashA_PortB_Dir = 0x3f;
 
	unsigned int delay = 0;
 
	while (1) {
 
		*pFlashA_PortB_Data = 0x15;	// b 010101
		ssync();
 
		// wait some time
		for (delay = 0x00FFFFFF; delay > 0; delay--);
 
		*pFlashA_PortB_Data = 0x2A;	// b 101010	
		ssync();
 
		// wait some time
		for (delay = 0x00FFFFFF; delay > 0; delay--);
	}
 
 
	// never reached
	//return 0;
 
}

Compiled with VisualDSP++ 5.0

Circular buffer queue in C

Tuesday, February 5th, 2008
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
/* CIRCULAR BUFFER QUEUE */
 
#include <stdio.h>
 
#define BUFFER_SIZE 8
 
int data_size = 0;      // number of chars in buffer
int read_pointer = 0;   // indice number of last read char
int write_pointer = 0;  // indice number of last written char
int input;              // user input 
char add;               // char to add
 
char buffer[BUFFER_SIZE];
 
// prototypes
int buffer_full(void);
int buffer_empty(void);
void push_char(char c);
void pull_char(void);
 
int main(void)
{
 
  int i; 
 
  printf("Circular Buffer Queue Implementation");  
 
  // make sure there are no random chars in array, all spaces
  for (i = 0; i < BUFFER_SIZE; i++) buffer[i] = 0x20;
 
  while (input != 4) {
 
    printf("\n    press 1 to push char");
    printf("\n    press 2 to pop char");
    printf("\n    press 3 to show queue");
    printf("\n    press 4 to exit\n");
    scanf("%d", &input);
 
    // push char
    if (input == 1) {
 
      printf("\nEnter char: ");
      scanf("%c", &add);
      scanf("%c", &add); // twice otherwise it will get the last enter as input
 
      if (! buffer_full())
        push_char(add);
      else
        printf("\nBUFFER IS FULL!");      
 
    }
    // pull char
    else if (input == 2) {
 
      if (! buffer_empty())
        pull_char();
      else
        printf("\nBUFFER IS EMPTY!");      
    }
    // display buffer info
    else if (input == 3) {
 
      printf("\n data_size: %d read_pointer: %d write_counter: %d", 
      data_size, read_pointer, write_pointer);
 
      printf("\nQueue content:\n");
      for (i = 0; i < BUFFER_SIZE; i++) printf("[%c]", buffer[i]);
 
    }
 
    printf("\n----");       
  } 
 
  return 0;
}
 
// adds a char
void push_char(char c)
{
    // increase write_pointer, check if at end of array
    if (++write_pointer >= BUFFER_SIZE) write_pointer = 0;
 
    buffer[write_pointer] = c;    
    data_size++;
}
 
// returns 1 if buffer is full, 0 if buffer is not full
int buffer_full(void) 
{
	return read_pointer == write_pointer &&
	 		data_size == BUFFER_SIZE;
}
// returns 1 if buffer is empty, 0 if buffer is not empty
int buffer_empty(void)
{
	return read_pointer == write_pointer && 
			data_size == 0;
}
 
// pull char from queue
void pull_char(void) 
{  
  if (++read_pointer >= BUFFER_SIZE) read_pointer = 0;
 
  printf("\nPopped char %c", buffer[read_pointer]);
 
  // enter space on place of read char so we can see it is removed
  buffer[read_pointer] = 0x20; 
  data_size--;  
}