Mico32 camera: Writing drivers based on mico32 camera

From ErikaWiki

Jump to: navigation, search

Contents

Introduction

This document is for programmers for writes drivers based on mico32_camera wishbone component. In the document examples we will refer camera values like follow figure:

mico32_camera values in the platform

Registers of the mico32_camera

Following registers are visible by the program:

Register Name Offset Num. Bits Type
ADDR 0x0 32 R/W
STATE 0x04 32 R
FLAG 0x08 32 R
CNTR1 0x0C 32 W
CNTR2 0x10 32 R/W
DIV 0x14 32 R/W
COUNT 0x18 32 R/W

All register are 32 bits. Some registers are read-only (STATE and FLAG), only one register is write-only (CNTR1), the remaining registers are read-write (ADDR, CNTR2, DIV and COUNT). In our example will use the follow mico32_camera register structure:

/* Camera controller registers */
typedef struct st_MicoCamera{
     void* volatile addr;
     volatile unsigned int state;
     volatile unsigned int flag;
     volatile unsigned int cntr1;
     volatile unsigned int cntr2;
     volatile unsigned int div;
     volatile unsigned int count;
} MicoCamera_t;

C code example to read a value from register

To get a register value (ADDR, STATE, FLAG, CNTR2, DIV and COUNT):

/* Offsets mico32_camera resister from address_base */ 
#define ADDR_OFF    0x00000000
#define STATE_OFF   0x00000004
#define FLAG_OFF    0x00000008
#define CNTR2_OFF   0x00000010
#define DIV_OFF     0x00000014
#define COUNT_OFF   0x00000018
  
int main(void) {
  
     /* Macro CAMERA_BASE_ADDRESS from system_conf.h */
     unsigned long *register = (CAMERA_BASE_ADDRESS + COUNT_OFF);
     unsigned long count_value;
     ...
     
     /* Read count register. */
     count_value = *register;     

     ...      
     return 0;
}

C code example to write a value to register

To set a register value (ADDR, CNTR1, DIV and COUNT):

#define ADDR_VALUE  0x00010000

/* Offsets mico32_camera resister from address_base */ 
#define ADDR_OFF    0x00000000
#define STATE_OFF   0x00000004
#define FLAG_OFF    0x00000008
#define CNTR2_OFF   0x00000010
#define DIV_OFF     0x00000014
#define COUNT_OFF   0x00000018
  
int main(void) {
  
     /* Macro CAMERA_BASE_ADDRESS from system_conf.h */
     unsigned long *register = (CAMERA_BASE_ADDRESS + ADDR_OFF);
     ...

     /* Write addr register. */
     *register = ADDR_VALUE;     

     ...
     return 0;
}

Registers description

The mico32_camera has seven registers. The functionality of each register is as described below.

ADDR register (dim: 32 bits, type: R/W, offset: 0x00, reset: 0x00000000)

When mico32_camera starts a new image acquisition, it stores the streaming camera data (32 bits at time) in the memory. After every data write in memory, the mico32_camera increments the internal pointer for next data write. The address base where the data writing begins is written in ADDR register.

ADDR register
Bit31 Bit30 ... Bit2 Bit1 Bit0
ADDR31 ADDR30 ... ADDR2 ADDR1 ADDR0

Example code:

  #define ADDR_VALUE  0x00010000
  /* Offsets mico32_camera resister from address_base */ 
  #define ADDR_OFF    0x00000000
  #define STATE_OFF   0x00000004
  #define FLAG_OFF    0x00000008
  #define CNTR2_OFF   0x00000010
  #define DIV_OFF     0x00000014
  #define COUNT_OFF   0x00000018
 
  int main(void) {
  
     /* Macro CAMERA_BASE_ADDRESS from system_conf.h */
     unsigned long *register = (CAMERA_BASE_ADDRESS + ADDR_OFF);
     ...
     /* Write addr register. */
     *register = ADDR_VALUE;     
     ...
     return 0;
  }

STATE register (dim: 32 bits, type: R, offset: 0x04)

The STATE register stores mico32_component's internal state information:

STATE register
Bit31 Bit30 ... Bit3 Bit2 Bit1 Bit0
- - ... - STATE2 STATE1 STATE0

Bits STATE2, STATE1 and STATE0 (STATE_S) (dim: 3 bits, type: R, offset: 0x00, reset: 000). Returns the state of the component.

  1. 000 => Reset
  2. 001 => Idle
  3. 010 => Waiting First
  4. 011 => Waiting Next
  5. 100 => Copying
  6. 101 => Copying Last

Example code:

/* Offsets mico32_camera resister from address_base */ 
#define ADDR_OFF    0x00000000
#define STATE_OFF   0x00000004
#define FLAG_OFF    0x00000008
#define CNTR2_OFF   0x00000010
#define DIV_OFF     0x00000014
#define COUNT_OFF   0x00000018

/* mico32_camera states */
#define RESET          0
#define IDLE           1
#define WAITING_FIRST  2
#define WAITING_NEXT   3
#define COPYING        4
#define COPYING_LAST   5
  
int main(void) {
  
     /* Macro CAMERA_BASE_ADDRESS from system_conf.h */
     unsigned long *register = (CAMERA_BASE_ADDRESS + STATE_OFF);
     unsigned long state;

     ...
     /* Waiting IDLE mico32_camera state */
     do {

          /* Read mico32_component's state */
          state = *register;

     } while (state != IDLE);
     
     ...
     return 0;

}

FLAG register (dim: 32 bits, type: R, offset: 0x08)

The FLAG register is composed of :

STATE register
Bit31 Bit30 ... Bit2 Bit1 Bit0
- - ... - SIZE_ERR ERR_FLAG IF_FLAG

Bit SIZE_ERR (dim: 1 bit, type: R, mask: 0x00000004, reset: 0)

If the image's size in bytes is different from the value register count, this bit is set. The control is turned off when the value register count is set to 0 (zero).

Example code:

#define MASK_SIZE_ERR 0x00000004

/* Size image: 640x480 colors (2 byte).
#define IMAGE_SIZE    (640*480*2)

/* Offsets mico32_camera resister from address_base */ 
#define ADDR_OFF      0x00000000
#define STATE_OFF     0x00000004
#define FLAG_OFF      0x00000008
#define CNTR2_OFF     0x00000010
#define DIV_OFF       0x00000014
#define COUNT_OFF     0x00000018
  
int main(void) {
  
     /* Macro CAMERA_BASE_ADDRESS from system_conf.h */
     unsigned long *register_count = (CAMERA_BASE_ADDRESS + COUNT_OFF);
     unsigned long *register_flag = (CAMERA_BASE_ADDRESS + FLAG_OFF);
     unsigned long bit_size_err;

     ...
     /* With a write in count register we enable the image size control. */
     *register_count = IMAGE_SIZE;

     ...
     /* Capture an image */

     ...
     /* Read bit SIZE_ERR */
     bit_size_err = *register_flag & MASK_SIZE_ERR;

     if (bit_size_err) {

           /* There was a size error */
           ...

     } else {

           /* There was not size error */
           ...
            
     }
     
     ...
     return 0;
}

Bit ERR_FLAG (dim: 1 bit, type: R, mask: 0x00000002, reset: 0)

If there was a Wishbone error (wire w_err on Wishbone bus) or an overflow in the Master FIFO this Flag is set high. The Flag will be reset when new frame starts.

Example code:

#define MASK_FLAG_ERR 0x00000002

/* Size image: 640x480 colors (2 byte).
#define IMAGE_SIZE    (640*480*2)

/* Offsets mico32_camera resister from address_base */ 
#define ADDR_OFF      0x00000000
#define STATE_OFF     0x00000004
#define FLAG_OFF      0x00000008
#define CNTR2_OFF     0x00000010
#define DIV_OFF       0x00000014
#define COUNT_OFF     0x00000018
  
int main(void) {
  
     /* Macro CAMERA_BASE_ADDRESS from system_conf.h */
     unsigned long *register_flag = (CAMERA_BASE_ADDRESS + FLAG_OFF);
     unsigned long bit_err_flag;

     ...
     /* Capture an image */
     ...

     /* Read bit ERR_FLAG */
     bit_err_flag = *register_flag & MASK_ERR_FLAG;

     /* Was there an error ?
     if (bit_err_flag) {

           /* There was a error on wishbone and/or overflow data fifo */
           ...
 
     } else {

           /* There was not error */
           ...
     }

     ...
     return 0;
}

Bit IF_FLAG (dim: 1 bit, type: R, mask: 0x00000001, reset: 0)

It is set at the end of an acquisition. In other words, when a frame has been completely written in the memory the flag change value from 0 logic to 1 logic. The Flag will be reset when new frame starts.

  1. from 0 to 1 => The mico32_camera switches from Writing Last state to Idle state or from Writing state to Waiting Next state. If IE_FLAG = 1'b1 an interrupt is raised.
  2. 0 => No frame has been completed.

Example code (we are waiting the end image capture polling on bit IF_FLAG):

#define MASK_IF_FLAG  0x00000001

/* Offsets mico32_camera resister from address_base */ 
#define ADDR_OFF      0x00000000
#define STATE_OFF     0x00000004
#define FLAG_OFF      0x00000008
#define CNTR2_OFF     0x00000010
#define DIV_OFF       0x00000014
#define COUNT_OFF     0x00000018
  
int main(void) {
     /* Macro CAMERA_BASE_ADDRESS from system_conf.h */
     unsigned long *register_flag = (CAMERA_BASE_ADDRESS + FLAG_OFF);
     unsigned long bit_if_flag;

     ...
     /* Start capture image */
     ...

     /* Read bit IF_FLAG for end capture */
     do {

           ...
           bit_if_flag = *register_flag & MASK_IF_FLAG;
           ...

     } while (!bit_if_flag);

     ...
     return 0;

}

CNTR1 register (dim: 32 bits, type: W, offset: 0x0000000C)

This register has three bits:

CNTR1 register
Bit31 Bit30 ... Bit2 Bit1 Bit0
- - ... CNTR_RST IF_RESET CNTR_S

Bit CNTR_START (dim: 1 bit, type: W, mask: 0x00000001, reset: -)

  1. When the programmer writes 1 logic in this bit the component starts an new acquisition.

Example code:

#define MASK_CNTR_START  0x00000001
  
/* Offsets mico32_camera resister from address_base */ 
#define ADDR_OFF         0x00000000
#define STATE_OFF        0x00000004
#define FLAG_OFF         0x00000008
#define CNTR1_OFF        0x0000000C
#define CNTR2_OFF        0x00000010
#define DIV_OFF          0x00000014
#define COUNT_OFF        0x00000018
  
int main(void) {
     
     /* Macro CAMERA_BASE_ADDRESS from system_conf.h */
     unsigned long *register_cntr1 = (CAMERA_BASE_ADDRESS + CNTR1_OFF);
     ...
     
     /* Start capture image */
     *register_cntr1 = MASK_CNTR_START;
     
     /* Read bit IF_FLAG for end capture */
     do {
       
           ...
           /* Polling bit IF_FLAG from FLAg register.
           bit_if_flag = *register_flag & MASK_IF_FLAG;
       
     } while (!bit_if_flag);

     ...
     return 0;
  }

Bit IF_RESET (dim: 1 bit, type: W, mask: 0x00000002, reset: -)

  1. The programmer writes “1” logic for acknowledge interrupt.

Example code:

#define MASK_CNTR_START  0x00000001
#define MASK_IF_RESET    0x00000002

/* Offsets mico32_camera resister from address_base */ 
#define ADDR_OFF         0x00000000
#define STATE_OFF        0x00000004
#define FLAG_OFF         0x00000008
#define CNTR1_OFF        0x0000000C
#define CNTR2_OFF        0x00000010
#define DIV_OFF          0x00000014
#define COUNT_OFF        0x00000018

/* Macro CAMERA_BASE_ADDRESS from system_conf.h */
unsigned long *register_cntr1 = (CAMERA_BASE_ADDRESS + CNTR1_OFF);

/* Prototype Interrupt handler end image acquisition */
void frame_isr(void);
  
int main(void) {

     /* Record handler camera interrupt 
        See: LatticeMico32 Software Developer User Guide, on Lattice Semiconductor Web site
        Enable Mico32 external interrupt (in this case from mico32_camera). 
     */
     MicoEnableInterrupt(mico32_camera_irq);	
     MicoRegisterISR(mico32_camera_irq, NULL, frame_isr);

     ...
     /* Start capture image */
     *register_cntr1 = MASK_CNTR_START;

     ...
     return 0;
}

/* Interrupt handler end image acquisition */
void frame_isr(void) {

     ...
     /* Acknowledge interrupt */
     *register_cntr1 = MASK_IF_RESET;

     ...
    
}

Bit CNTR_RST (dim: 1 bit, type: W, mask: 0x00000004, reset: -)

  1. If the programmer writes 1 logic in this bit, the component switches to Reset state.

Example code:

#define MASK_CNTR_RST    0x00000004

/* Offsets mico32_camera resister from address_base */ 
#define ADDR_OFF         0x00000000
#define STATE_OFF        0x00000004
#define FLAG_OFF         0x00000008
#define CNTR1_OFF        0x0000000C
#define CNTR2_OFF        0x00000010
#define DIV_OFF          0x00000014
#define COUNT_OFF        0x00000018
 
int main(void) {

     /* Macro CAMERA_BASE_ADDRESS from system_conf.h */
     unsigned long *register_state = (CAMERA_BASE_ADDRESS + STATE_OFF);
     unsigned long *register_cntr1 = (CAMERA_BASE_ADDRESS + CNTR1_OFF);
     unsigned lond state;
  
     /* Reset mico32_camera */
     *register_cntr1 = MASK_CNTR_RST;

     /* Waiting IDLE mico32_camera state */
     do {
    
           state = *register_state;
           ...

     } while (state != IDLE);  

  ...
  return 0;
}

CNTR2 register (dim: 32 bits, type: R/W, offset: 0x00000010)

This register has one bit:

CNTR2 register
Bit31 Bit30 ... Bit2 Bit1 Bit0
- - ... - - IE_FLAG

Bit IE_FLAG (dim: 1 bit, type: R/W, mask: 0x00000001, reset: 0)

  1. The programmer writes “1” logic for interrupt camera enable (mico32_camera is enabled to send an interrupt).

Example code:

#define MASK_IE_FLAG     0x00000001
#define MASK_CNTR_START  0x00000001
#define MASK_IF_RESET    0x00000002

/* Offsets mico32_camera resister from address_base */ 
#define ADDR_OFF         0x00000000
#define STATE_OFF        0x00000004
#define FLAG_OFF         0x00000008
#define CNTR1_OFF        0x0000000C
#define CNTR2_OFF        0x00000010
#define DIV_OFF          0x00000014
#define COUNT_OFF        0x00000018

/* Macro CAMERA_BASE_ADDRESS from system_conf.h */
unsigned long *register_cntr1 = (CAMERA_BASE_ADDRESS + CNTR1_OFF);
unsigned long *register_cntr2 = (CAMERA_BASE_ADDRESS + CNTR2_OFF);

/* Prototype Interrupt handler end image acquisition */
void frame_isr(void);
  
int main(void) {

     /* Record handler camera interrupt 
        See: LatticeMico32 Software Developer User Guide, on Lattice Semiconductor Web site
        Enable Mico32 external interrupt (in this case from mico32_camera). 
     */
     MicoEnableInterrupt(mico32_camera_irq);	
     MicoRegisterISR(mico32_camera_irq, NULL, frame_isr);

     /* mico32_camera is enabled to send an interrupt */
     *register_cntr2 = MASK_IE_FLAG;

     ...
     /* Start capture image */
     *register_cntr1 = MASK_CNTR_START;

     ...
     return 0;
}

/* Interrupt handler end image acquisition */
void frame_isr(void) {

     ...
     /* Acknowledge interrupt */
     *register_cntr1 = MASK_IF_RESET;

     ...    
}

DIV register (dim: 32 bits, type: R/W, offset: 0x00000014)

DIV register
Bit31 Bit30 ... Bit8 Bit7 Bit6 Bit5 Bit4 Bit3 Bit2 Bit1 Bit0
- - ... - DIV7 DIV6 DIV5 DIV4 DIV3 DIV2 DIV1 DIV0

This register set the period clock to mico32_camera. The clock's mico32_camera will be 2*(platform_freq/(div_value+1)).

Example code:

/* Platform clock is 50MHz */
#define PLATFORM_CLK     50000000UL

/* Offsets mico32_camera resister from address_base */ 
#define ADDR_OFF         0x00000000
#define STATE_OFF        0x00000004
#define FLAG_OFF         0x00000008
#define CNTR1_OFF        0x0000000C
#define CNTR2_OFF        0x00000010
#define DIV_OFF          0x00000014
#define COUNT_OFF        0x00000018

/* Macro CAMERA_BASE_ADDRESS from system_conf.h */
unsigned long *register_div = (CAMERA_BASE_ADDRESS + DIV_OFF);

int main(void) {

     ...
     /* With div_value = 3 the mico32_camera will be: (2*50)/(3+1) = 25MHz */
     *register_div = 3;

     ...
     return 0;
}

COUNT register (dim: 32 bits, type: R/W, offset: 0x00000018)

This register should be set to the value of image size (in bytes). If we don't require the control image, we write 0 (zero) value.

Example code:

/* The camera is set on resolution: 640x480x2 */
#define IMAGE_SIZE       (640*480*2)

/* Offsets mico32_camera resister from address_base */ 
#define ADDR_OFF         0x00000000
#define STATE_OFF        0x00000004
#define FLAG_OFF         0x00000008
#define CNTR1_OFF        0x0000000C
#define CNTR2_OFF        0x00000010
#define DIV_OFF          0x00000014
#define COUNT_OFF        0x00000018

/* Macro CAMERA_BASE_ADDRESS from system_conf.h */
unsigned long *register_count = (CAMERA_BASE_ADDRESS + COUNT_OFF);

int main(void) {

     ...
     /* We expect a size of 640 * 480 * 2 */
     *register_count = IMAGE_SIZE;

     ...
     return 0;
}

How the mico32_camera works

The mico32_camera has six states. The state scan be read with register STATE. They are:

States mico32_camera component
  1. Reset: STATE_BITS = 3'b000. In the Reset state the component sends an impulse on the reset signal to the Camera. It resets also all the other components. Then it changes state on the first impulse signal Vsync.
  1. Idle: STATE_BITS = 3'b001. The mico32_camera wait a new start command for a capture frame.
  1. Waiting First: STATE_BITS = 3'b010. After a new start command the mico32_camera switches in the Waiting First. So it waits the start of a new frame. When a new frame begins the mico32_camera switches to the Copying Last state. When the mico32_camera is in Waiting First and it receives another start command, the component switches to Waiting Next and the ADDR register is stored in internal buffer; its value will be used for the frame after the next.
  1. Waiting Next: STATE_BITS = 3'b011. The component is waiting for the start of a new frame; the frame after the next is scheduled to be written in memory. When a new frame begins the component switches to the Copying state. If the component receives a new start command nothing happens.
  1. Copying: STATE_BITS = 3b'100. The component is writing the current frame into the memory; the frame after the current is scheduled to be written in memory. When the writing finishes the component sets FLAG_IF and switches to state Waiting First. If FLAG_IE = 1'b1 it generates an interrupt. If the component receives a new start command nothing happens.
  1. Copying Last: STATE_BITS = 3'b101. The component is writing a frame into the memory; no other frame is scheduled to be written in memory. When the writing finishes the component sets FLAG_IF and switches to the IDLE state. If FLAG_IE = 1'b1 it generates an interrupt. If the component receives a new start command, the component switches to Copying state and the ADDR register is read; the value read will be used for the frame after the current.

If a reset command (CNTR_RST is asserted) is received when component is any state different from Reset, it switches to the Reset state.

Simple C code for manager mico32_camera

In all examples will use the following macros (which can be placed in a header file):

/* Offsets resister from mico32_camera's address_base */ 
#define ADDR_OFF         0x00000000
#define STATE_OFF        0x00000004
#define FLAG_OFF         0x00000008
#define CNTR1_OFF        0x0000000C
#define CNTR2_OFF        0x00000010
#define DIV_OFF          0x00000014
#define COUNT_OFF        0x00000018
  
/* Mico32_camera states from STATE register */
#define RESET          0
#define IDLE           1
#define WAITING_FIRST  2
#define WAITING_NEXT   3
#define COPYING        4
#define COPYING_LAST   5
  
/* Masks bit FLAG register */
#define MASK_IF_FLAG  0x00000001
#define MASK_FLAG_ERR 0x00000002
#define MASK_SIZE_ERR 0x00000004
  
/* Masks bit CNTR1 register */
#define MASK_CNTR_START  0x00000001
#define MASK_IF_RESET    0x00000002
#define MASK_CNTR_RST    0x00000004
  
/* Mask bit CNTR2 register */
#define MASK_IE_FLAG     0x00000001

Now we will use a very simple C code for the acquisition of an image (no control size for now). We will use the technique of polling on the state registers:

unsigned long *reg_addr  = (CAMERA_BASE_ADDRESS + ADDR_OFF);
unsigned long *reg_state = (CAMERA_BASE_ADDRESS + STATE_OFF);
unsigned long *reg_flag  = (CAMERA_BASE_ADDRESS + FLAG_OFF);
unsigned long *reg_cntr1 = (CAMERA_BASE_ADDRESS + CNTR1_OFF);
unsigned long *reg_cntr2 = (CAMERA_BASE_ADDRESS + CNTR2_OFF);
unsigned long *reg_div   = (CAMERA_BASE_ADDRESS + DIV_OFF);
unsigned long *reg_count = (CAMERA_BASE_ADDRESS + COUNT_OFF);

unsigned long state;

int main(void) {
     
     /* Reset mico32_camera: Recommended */
     *register_cntr1 = MASK_CNTR_RST;
     
     /* After a software reset the mico32_camera goes in RESET state.
        Then at first vsync camera signal the mico32_camera switches in IDLE state.
        No timeout in this code */
     do {
        
           /* Polling mico32_camera state */
           state = *register_state;
        
     } while (state != IDLE);  
     
     /* Set address memory acquisition of the image */
     *reg_addr = ADDR_VALUE;
     
     /* Clock camera is 4 time less than platform clock */
     *reg_div = 3;
     
     /* Start acquisition */
     *register_cntr1 = MASK_CNTR_START;
     
     /* Waiting the end of the acquisition (return mico32_camera in IDLE state) */
     do {
     
           /* Polling mico32_camera state */
           state = *register_state;
     
     } while (state != IDLE); 
  
     /* Now the image is available from the address ADDR_VALUE */
     ...
  
     return 0;
   }

Same code with control of image size:

unsigned long *reg_addr  = (CAMERA_BASE_ADDRESS + ADDR_OFF);
unsigned long *reg_state = (CAMERA_BASE_ADDRESS + STATE_OFF);
unsigned long *reg_flag  = (CAMERA_BASE_ADDRESS + FLAG_OFF);
unsigned long *reg_cntr1 = (CAMERA_BASE_ADDRESS + CNTR1_OFF);
unsigned long *reg_cntr2 = (CAMERA_BASE_ADDRESS + CNTR2_OFF);
unsigned long *reg_div   = (CAMERA_BASE_ADDRESS + DIV_OFF);
unsigned long *reg_count = (CAMERA_BASE_ADDRESS + COUNT_OFF);

unsigned long state;

int main(void) {

     /* Reset mico32_camera: Recommended */
     *register_cntr1 = MASK_CNTR_RST;
  
     /* After a software reset the mico32_camera goes in RESET state.
        Then at first vsync camera signal the mico32_camera switches in IDLE state.
        No timeout in this code 
     */
     do {
           
           /* Read the mico32_camera's state */
           state = *register_state;

     } while (state != IDLE);  
  
     /* Set address memory acquisition of the image */
     *reg_addr = ADDR_VALUE;
  
     /* Clock camera is 4 time less than platform clock */
     *reg_div = 3;
  
     /* The camera is set @ 320 x 240 x 1 */
     *reg_count = IMAGE_SIZE;
  
     /* Start acquisition */
     *register_cntr1 = MASK_CNTR_START;
  
     /* Waiting the end of the acquisition (return mico32_camera in IDLE state) */
     do {

           /* Read the mico32_camera's state */
           state = *register_state;

     } while (state != IDLE);
  
     /* size error? */
     if (*reg_flag & MASK_SIZE_ERR) {

           /* Something goes wrong, maybe different camera resolution */
           ...

     } else {

           /* Now the image is available from the address ADDR_VALUE */
           ...
     }
  
     ...
  
     return 0;
}
Personal tools