WB_JPGDEC_V2 - Operational Overview
The following sections take a look at initialization of the WB_JPGDEC_V2 and example usage.
Initialization
After an external reset on the RST_I line, you will need to initialize the WB_JPGDEC_V2. This should be carried out in accordance with design requirements and can include:
- Loading the Interrupt Mask register with a value that will enable the required interrupts for the peripheral.
- If you want to decode a specific area of the JPEG, load the START_X, START_Y, END_X and END_Y registers, with the left column, right column, top line and bottom line respectively.
- Setup the input buffer for decoding by loading the starting address for the buffer into the Read Address register and the size of the buffer into the Read Count register.
- Setup the output buffer for decoding by loading the starting address for the buffer into the Write Start Address register, the end address for the buffer into the Write End Address register and the width for an output line (in pixels) into the Write Width register. If you need to offset the location, enter the offset value into the Write Offset register.
Once the registers have been set as required, simply write a '1' to the start
bit in the Status register (STATUS.7), to begin decoding. Once the image has been successfully decoded, the WB_JPGDEC_V2 will remain in the ready state (jpgrdy
bit set in the Status register). To decode another image, you will again need to write '1' to the start
bit in the Status register.
If you issue a soft reset, by writing '1' to the rst
bit of the Status register (STATUS.8), the processor-accessible internal registers themselves are not reset and therefore will retain their previous values. You may, however, need to adjust the values in the Read Address and Read Count registers before restarting the decoder.
Example Usage
To better illustrate the use of the internal registers, the following sections provide examples of how the WB_JPGDEC_V2 peripheral can be used. All examples are written in pseudo code.
Decoding to Memory
The decoded image will end up in the output buffer with no gaps between lines.
READ_ADDR = start of JPG image
READ_COUNT = size of JPG image;
WRITE_STARTADDR = begin output buffer
WRITE_ENDADDR = end of output buffer
WRITE_OFFSET = 0
WRITE_WIDTH = 0
START_X = 0
START_Y = 0
END_X = 0
END_Y = 0
STATUS.START = 1
Loop
{
if STATUS.JPGRDY then quit, all went OK
if STATUS.JPGERR then quit, should not happen
if STATUS.REMPTY then quit, should not happen
if STATUS.WFULL then quit, should not happen
}
Decoding to a Screen Buffer in Memory
The decoded image will end up in the screen buffer with each line starting at WRITE_WIDTH intervals. If lines are longer than WRITE_WIDTH the additional pixels will be discarded.
READ_ADDR = start of JPG image
READ_COUNT = size of JPG image;
WRITE_STARTADDR = begin screen buffer
WRITE_ENDADDR = end of screen buffer
WRITE_OFFSET = 0
WRITE_WIDTH = width of screen line
START_X = 0
START_Y = 0
END_X = width of screen
END_Y = height of screen
STATUS.START = 1
Loop
{
if STATUS.JPGRDY then quit, all went OK
if STATUS.JPGERR then quit, should not happen
if STATUS.REMPTY then quit, should not happen
if STATUS.WFULL then quit, should not happen
}
Block-Based Reading of JPEG Data from a Small Buffer
A possible use for this implementation is reading the JPEG image from hard disk, where data transfer takes place in blocks of fixed size.
The decoded image will end up in the output buffer (presumed large enough in this example) with no gaps between lines.
READ_ADDR = 0
READ_COUNT = 0;
WRITE_STARTADDR = begin output buffer
WRITE_ENDADDR = end of output buffer
WRITE_OFFSET = 0
WRITE_WIDTH = 0
START_X = 0
START_Y = 0
END_X = 0
END_Y = 0
STATUS.START = 1
Loop
{
if STATUS.JPGRDY then quit, all went OK
if STATUS.JPGERR then quit, should not happen
if STATUS.WFULL then quit, should not happen
if STATUS.REMPTY then
read next part from JPG data into read buffer
READ_ADDR = start of read buffer
READ_COUNT = size of data read
STATUS.REMPTY = 1
}
Block-Based Writing of Decoded Image to a Small Buffer in Fixed Sets of Image Lines
A possible use for this implementation is when running image processing over the decoded image before displaying it on a screen. This way only a buffer for 16 screen lines is needed instead of a buffer for a full screen.
JPEG images are always decoded in batches of 8 or 16 lines at a time, depending on the way they are compressed. For this implementation to be usable under all circumstances a buffer of a multiple of 16 lines is required. If this requirement is met this will guarantee ProcessLines(buffer, line_width, number_of_lines) will be called in top-down order once for each set of 16 (or at the last call possibly less) image lines decoded.
READ_ADDR = start of JPG image
READ_COUNT = size of JPG image;
WRITE_STARTADDR = 0
WRITE_ENDADDR = 0
WRITE_OFFSET = 0
WRITE_WIDTH = 0
START_X = 0
START_Y = 0
END_X = 0
END_Y = 0
buffer = void
lines_in_buffer = 16 (can be any multiple of 16)
STATUS.START = 1
Loop
{
if STATUS.JPGERR then quit, should not happen
if STATUS.REMPTY then quit, should not happen
if STATUS.WFULL or STATUS.JPGRDY then
if buffer = void then
allocate buffer with size (lines_in_buffer * SIZE_X_EVEN) in pixels
WRITE_STARTADDR = begin of buffer
WRITE_ENDADDR = end of buffer
lines_to_decode = SIZE_Y
else
if lines_in_buffer < lines_to_decode then
lines_in_buffer = lines_to_decode
lines_to_decode = lines_to_decode - lines_in_buffer;
call ProcessLines(buffer, SIZE_X_EVEN, lines_in_buffer)
WRITE_OFFSET = WRITE_OFFSET + size of buffer
if STATUS.JPGRDY then quit, all went OK
STATUS.WFULL = 1
}
Block-Based Writing of Decoded Image using a Small Buffer of Arbitrary Size
A possible use for this implementation is storing the resulting image on hard disk, where data transfer takes place in blocks of fixed size.
The image will decode into a small buffer, which will be swapped with offline storage while decoding. As the buffer size is not a precise multiple of 16 image lines, the decoder will want to write more than once in every buffer sized part of the image. This means that data must be updated two-way with the offline storage, writing only is not sufficient.
-- In this code we divide the memory for the decoded image in imaginary
-- blocks the size of the work buffer.
--
-- As the decoder wants to write a pixel, the work buffer is filled with the
-- corresponding block from the full image. As soon as the decoder wants to
-- write a pixel outside the block currently in the work buffer, it halts.
-- We then copy the work buffer back to its place in the full image.
-- This process repeats until the complete image has been decoded.
READ_ADDR = start of JPG image
READ_COUNT = size of JPG image;
WRITE_STARTADDR = start of work buffer
WRITE_ENDADDR = end of work buffer
WRITE_OFFSET = 0
WRITE_WIDTH = 0
START_X = 0
START_Y = 0
END_X = 0
END_Y = 0
mirror offline storage at WRITE_OFFSET to the work buffer
STATUS.START = 1
Loop
{
if STATUS.JPGERR then quit, should not happen
if STATUS.REMPTY then quit, should not happen
if STATUS.WFULL or STATUS.JPGRDY then
mirror work buffer to offline storage at WRITE_OFFSET
if STATUS.JPGRDY then quit, all went OK
-- find location in the image the decoder would want to write:
image_offset = WRITE_OFFSET WRITE_ADDR - WRITE_STARTADDR
-- if we divided the image into multiple areas of the size of
-- our work buffer, find out which of them the decoder would
-- want to write:
offset_blocknumber = floor(image_offset / size_of_workbuffer)
-- now we know where the block we want to mirror is located:
WRITE_OFFSET = offset_blocknumber x size_of_workbuffer
mirror offline storage at WRITE_OFFSET to the work buffer
STATUS.WFULL = 1
}