-- raspilcd, a simple tool to display bmp pictures & text on a ST7565 LCD -- Copyright (C) 2014 Torsten Meissner -- -- This program is free software: you can redistribute it and/or modify -- it under the terms of the GNU General Public License as published by -- the Free Software Foundation, either version 3 of the License, or -- (at your option) any later version. -- -- This program is distributed in the hope that it will be useful, -- but WITHOUT ANY WARRANTY; without even the implied warranty of -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -- GNU General Public License for more details. -- -- You should have received a copy of the GNU General Public License -- along with this program. If not, see http://www.gnu.org/licenses/. with Interfaces; use Interfaces; with Interfaces.C; use Interfaces.C; with Interfaces.C.extensions; use Interfaces.C.extensions; with bcm2835_h; use bcm2835_h; with Ada.Text_IO; use Ada.Text_IO; package body st7565lcd is procedure io_init is begin bcm2835_gpio_fsel(pin => LCD_CS, mode => unsigned_char(BCM2835_GPIO_FSEL_OUTP)); bcm2835_gpio_fsel(pin => LCD_RST, mode => unsigned_char(BCM2835_GPIO_FSEL_OUTP)); bcm2835_gpio_fsel(pin => LCD_A0, mode => unsigned_char(BCM2835_GPIO_FSEL_OUTP)); bcm2835_gpio_fsel(pin => LCD_CLK, mode => unsigned_char(BCM2835_GPIO_FSEL_OUTP)); bcm2835_gpio_fsel(pin => LCD_SI, mode => unsigned_char(BCM2835_GPIO_FSEL_OUTP)); end io_init; procedure lcd_init is begin -- reset bcm2835_gpio_write(pin => LCD_CS, on => unsigned_char(HIGH)); bcm2835_delayMicroseconds(unsigned_long_long(1)); bcm2835_gpio_write(pin => LCD_RST, on => unsigned_char(LOW)); bcm2835_delayMicroseconds(unsigned_long_long(1)); bcm2835_gpio_write(pin => LCD_RST, on => unsigned_char(HIGH)); bcm2835_delayMicroseconds(unsigned_long_long(1)); -- init routine for index in lcd_init_data'range loop lcd_transfer_data(value => lcd_init_data(index), si => false); end loop; lcd_clear; end lcd_init; -- display strings on the lcd at a given position -- data is a string with any allowed range -- for strings not beginning at 0 we have to decrement the index -- variable for xpos by the value of the range begin, so we get -- for xpos a range from (xpos + 0 .. xpos + number of char in string) procedure lcd_ascii57_string (xpos : natural; ypos : natural; data : string) is begin for index in data'range loop lcd_ascii57(xpos => xpos + (index - data'first) * 6, ypos => ypos, data => character'val(character'pos(data(index)))); end loop; end lcd_ascii57_string; procedure lcd_ascii57 (xpos : natural; ypos : natural; data : character) is begin lcd_set_page(page => ypos, column => xpos); -- write one 5x7 char for index in 0..4 loop lcd_transfer_data(value => font_5x7(character'pos(data))(index), si => true); end loop; -- one free column between chars lcd_transfer_data(value => 16#00#, si => true); end lcd_ascii57; procedure lcd_picture (xpos : natural; ypos: natural; picture : t_lcd_array) is begin for outdex in 0..7 loop lcd_set_page(page => ypos + outdex, column => xpos); for index in (128 * outdex) .. (128 * (outdex + 1) - 1) loop lcd_transfer_data(value => picture(index), si => true); end loop; end loop; end lcd_picture; procedure lcd_clear is begin bcm2835_gpio_write(pin => LCD_CS, on => unsigned_char(LOW)); for outdex in 0..7 loop lcd_set_page(page => outdex, column => 0); for index in 0..128 loop lcd_transfer_data(value => 16#00#, si => true); end loop; end loop; bcm2835_gpio_write(pin => LCD_CS, on => unsigned_char(HIGH)); end lcd_clear; procedure lcd_transfer_data (value : byte; si : boolean) is begin bcm2835_gpio_write(pin => LCD_CS, on => unsigned_char(LOW)); bcm2835_gpio_write(pin => LCD_CLK, on => unsigned_char(HIGH)); if si then bcm2835_gpio_write(pin => LCD_A0, on => unsigned_char(HIGH)); else bcm2835_gpio_write(pin => LCD_A0, on => unsigned_char(LOW)); end if; lcd_byte(value); bcm2835_gpio_write(pin => LCD_CS, on => unsigned_char(HIGH)); end lcd_transfer_data; procedure lcd_set_page (page : natural; column : natural) is lsb : byte := byte(column + 1) and 16#0f#; msb : byte := byte(column + 1) and 16#f0#; page_int : byte := byte(page) or 16#b0#; begin msb := Shift_Right(msb, 4); msb := msb or 16#10#; lcd_transfer_data(value => page_int, si => false); lcd_transfer_data(value => msb, si => false); lcd_transfer_data(value => lsb, si => false); null; end lcd_set_page; procedure lcd_byte (data : byte) is data_int : byte := data; begin for index in 0..7 loop bcm2835_delayMicroseconds(unsigned_long_long(1)); bcm2835_gpio_write(pin => LCD_CLK, on => unsigned_char(LOW)); if (data_int and 16#80#) = 16#80# then bcm2835_gpio_write(pin => LCD_SI, on => unsigned_char(HIGH)); else bcm2835_gpio_write(pin => LCD_SI, on => unsigned_char(LOW)); end if; data_int := Shift_Left(data_int, 1); bcm2835_delayMicroseconds(unsigned_long_long(1)); bcm2835_gpio_write(pin => LCD_CLK, on => unsigned_char(HIGH)); end loop; end lcd_byte; function bmp_to_lcd (bmp_picture : t_bmp_picture) return t_lcd_array is lcd : t_lcd_array := (others => 16#00#); logic : byte; begin for aussen in 0 .. 7 loop logic := 16#01#; for outdex in 0 .. 7 loop for index in 0 .. 127 loop if ((bmp_picture.data(aussen * 1024 + outdex * 128 + index)(which_byte(bmp_picture.mask.red)) or bmp_picture.data(aussen * 1024 + outdex * 128 + index)(which_byte(bmp_picture.mask.green)) or bmp_picture.data(aussen * 1024 + outdex * 128 + index)(which_byte(bmp_picture.mask.blue))) < 16#88#) then lcd(aussen * 128 + index) := lcd(aussen * 128 + index) or logic; end if; end loop; logic := Shift_Left(logic, 1); end loop; end loop; return lcd; end bmp_to_lcd; function which_byte (data : dword) return integer is begin case data is when 16#000000FF# => return 0; when 16#0000FF00# => return 1; when 16#00FF0000# => return 2; when 16#FF000000# => return 3; when others => raise mask_exception; end case; end which_byte; -- read_bmp : read a bmp file in t_bmp_picture record procedure read_bmp (file : in Ada.Streams.Stream_IO.File_Type; file_access : access Ada.Streams.Root_Stream_Type'Class; bmp_picture : in out t_bmp_picture) is begin -- read header t_bmp_header'Read(file_access, bmp_picture.header); -- check for valid header if (abs bmp_picture.header.biHeight /= 64 or bmp_picture.header.biWidth /= 128 or (bmp_picture.header.biCompression /= 0 and bmp_picture.header.biCompression /= 3) or bmp_picture.header.biBitCount /= 32) then raise bmp_exception; end if; -- get color map if existing if bmp_picture.header.biCompression = 3 then t_color_mask'Read(file_access, bmp_picture.mask); end if; -- read in image data if bmp_picture.header.biHeight < 0 then -- top-down pixel matrix for index in bmp_picture.data'range loop if not Ada.Streams.Stream_IO.End_Of_File(file) then t_byte_array'Read(file_access, bmp_picture.data(index)); end if; end loop; else -- bottom-top pixel matrix for row in reverse 0 .. 63 loop for column in 0 .. 127 loop if not Ada.Streams.Stream_IO.End_Of_File(file) then t_byte_array'Read(file_access, bmp_picture.data(row * 128 + column)); end if; end loop; end loop; end if; end read_bmp; end st7565lcd;