OpenCores
URL https://opencores.org/ocsvn/openarty/openarty/trunk

Subversion Repositories openarty

Compare Revisions

  • This comparison shows the changes necessary to convert path
    /
    from Rev 34 to Rev 35
    Reverse comparison

Rev 34 → Rev 35

/openarty/trunk/sw/board/oledtest.c
1,3 → 1,45
////////////////////////////////////////////////////////////////////////////////
//
// Filename: oledtest.c
//
// Project: OpenArty, an entirely open SoC based upon the Arty platform
//
// Purpose: To see whether or not we can display an image onto the OLEDrgb
// PMod. This program runs on the ZipCPU internal to the FPGA,
// and commands the OLEDrgb to power on, reset, initialize, and then to
// display an alternating pair of images onto the display.
//
//
// Creator: Dan Gisselquist, Ph.D.
// Gisselquist Technology, LLC
//
////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2015-2016, Gisselquist Technology, LLC
//
// This program is free software (firmware): 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 MERCHANTIBILITY 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. (It's in the $(ROOT)/doc directory, run make with no
// target there if the PDF file isn't present.) If not, see
// <http://www.gnu.org/licenses/> for a copy.
//
// License: GPL, v3, as defined and found on www.gnu.org,
// http://www.gnu.org/licenses/gpl.html
//
//
////////////////////////////////////////////////////////////////////////////////
//
//
 
#include "artyboard.h"
#include "zipsys.h"
 
15,8 → 57,7
#define OLED_VCC_DISABLE 0x0020000
#define OLED_RESET 0x0040000
#define OLED_RESET_CLR 0x0040004
#define OLED_PWRRESET (OLED_PMODEN|OLED_RESET) // 5
#define OLED_FULLPOWER (OLED_PMODEN|OLED_VCCEN|OLED_RESET_CLR) // 3->7
#define OLED_FULLPOWER (OLED_PMODEN|OLED_VCCEN|OLED_RESET_CLR)
#define OLED_POWER_DOWN (OLED_PMODEN_OFF|OLED_VCC_DISABLE)
#define OLED_BUSY 1
#define OLED_DISPLAYON 0x0af
26,51 → 67,15
 
#define OLED_DISPLAY_OFF
 
const int init_sequence[] = {
// Unlock commands
0x01fd12,
// Display off
0x0ae,
// Set remap and data format
0x01a072,
// Set the start line
0x01a100,
// Set the display offset
0x01a200,
// Normal display mode
0x0000a4,
// Set multiplex ratio
0x01a83f,
// Set master configuration:
// Use External VCC
0x01ad8e,
// Disable power save mode
0x01b00b,
// Set phase length
0x01b131,
// Set clock divide
0x01b3f0,
// Set Second Pre-change Speed For ColorA
0x018a64,
// 5l) Set Set Second Pre-charge Speed of Color B
0x018b78,
// 5m) Set Second Pre-charge Speed of Color C
0x018c64,
// 5n) Set Pre-Charge Voltage
0x01bb3a,
// 50) Set VCOMH Deselect Level
0x01be3e,
// 5p) Set Master Current
0x018706,
// 5q) Set Contrast for Color A
0x018191,
// 5r) Set Contrast for Color B
0x018250,
// 5s) Set Contrast for Color C
0x01837D,
// disable scrolling
0x02e };
 
 
/*
* timer_delay()
*
* Using the timer peripheral, delay by a given number of counts. We'll sleep
* during this delayed time, and wait on an interrupt to wake us. As a result,
* this will only work from supervisor mode.
*/
void timer_delay(int counts) {
// Clear the PIC. We want to exit from here on timer counts alone
zip->pic = CLEARPIC;
84,8 → 89,76
} // else anything less has likely already passed
}
 
 
void oled_clear(void);
 
/*
* The following outlines a series of commands to send to the OLEDrgb as part
* of an initialization sequence. The sequence itself was taken from the
* MPIDE demo. Single byte numbers in the sequence are just that: commands
* to send 8-bit values across the port. 17-bit values with the 16th bit
* set send two bytes (bits 15-0) to the port. The OLEDrgb treats these as
* commands (first byte) with an argument (the second byte).
*/
const int init_sequence[] = {
// Unlock commands
0x01fd12,
// Display off
0x0ae,
// Set remap and data format
0x01a072,
// Set the start line
0x01a100,
// Set the display offset
0x01a200,
// Normal display mode
0x0000a4,
// Set multiplex ratio
0x01a83f,
// Set master configuration:
// Use External VCC
0x01ad8e,
// Disable power save mode
0x01b00b,
// Set phase length
0x01b131,
// Set clock divide
0x01b3f0,
// Set Second Pre-change Speed For ColorA
0x018a64,
// 5l) Set Set Second Pre-charge Speed of Color B
0x018b78,
// 5m) Set Second Pre-charge Speed of Color C
0x018c64,
// 5n) Set Pre-Charge Voltage
0x01bb3a,
// 50) Set VCOMH Deselect Level
0x01be3e,
// 5p) Set Master Current
0x018706,
// 5q) Set Contrast for Color A
0x018191,
// 5r) Set Contrast for Color B
0x018250,
// 5s) Set Contrast for Color C
0x01837D,
// disable scrolling
0x02e
};
 
/*
* oled_init()
*
* This initializes and starts up the OLED. While it sounds important, really
* the majority of the work necessary to do this is really captured in the
* init_sequence[] above. This just primarily works to send that sequence to
* the PMod.
*
* We should be able to do all of this with the DMA: wait for an OLEDrgb not
* busy interrupt, send one value, repeat until done. For now ... we'll just
* leave that as an advanced exercise.
*
*/
void oled_init(void) {
int i;
 
95,15 → 168,11
sys->io_oled.o_ctrl = init_sequence[i];
}
 
// 5u) Clear Screen
oled_clear();
 
zip->tma = (CLOCKFREQ_HZ/200);
zip->pic = EINT(SYSINT_TMA);
zip_rtu();
zip->pic = CLEARPIC;
// Wait 5ms
timer_delay(CLOCKFREQ_HZ/200);
 
 
// Turn on VCC and wait 100ms
sys->io_oled.o_data = OLED_VCCEN;
// Wait 100 ms
110,9 → 179,23
timer_delay(CLOCKFREQ_HZ/10);
 
// Send Display On command
sys->io_oled.o_ctrl = 0xaf;
}
sys->io_oled.o_ctrl = OLED_DISPLAYON;
}
 
/*
* oled_clear()
*
* This should be fairly self-explanatory: it clears (sets to black) all of the
* graphics memory on the OLED.
*
* What may not be self-explanatory is that to send any more than three bytes
* using our interface you need to send the first three bytes in o_ctrl,
* and set the next bytes (up to four) in o_a. (Another four can be placed in
* o_b.) When the word is written to o_ctrl, the command goes over the wire
* and o_a and o_b are reset. Hence we set o_a first, then o_ctrl. Further,
* the '4' in the top nibble of o_ctrl indicates that we are sending 5-bytes
* (4+5), so the OLEDrgb should see: 0x25,0x00,0x00,0x5f,0x3f.
*/
void oled_clear(void) {
while(sys->io_oled.o_ctrl & OLED_BUSY)
;
122,6 → 205,11
;
}
 
/*
* oled_fill
*
* Similar to oled_clear, this fills a rectangle with a given pixel value.
*/
void oled_fill(int c, int r, int w, int h, int pix) {
int ctrl; // We'll send this value out the control/command port
 
139,20 → 227,31
;
sys->io_oled.o_ctrl = 0x12601;
 
//
// Now, let's build the actual copy command
//
// This is an 11 byte command, consisting of the 0x22, followed by
// the top left column and row of our rectangle, and then the bottom
// right column and row. That's the first five bytes. The next six
// bytes are the color of the border and the color of the fill.
// Here, we set both colors to be identical.
//
ctrl = 0xa0220000 | ((c&0x07f)<<8) | (r&0x03f);
sys->io_oled.o_a = (((c+w)&0x07f)<<24) | (((r+h)&0x03f)<<16);
sys->io_oled.o_a|= ((pix >> 11) & 0x01f)<< 9;
sys->io_oled.o_a|= ((pix >> 5) & 0x03f) ;
sys->io_oled.o_b = ((pix >> 11) & 0x01f)<<17;
sys->io_oled.o_b = ((pix ) & 0x01f)<<25;
sys->io_oled.o_b|= ((pix >> 11) & 0x01f)<<17;
sys->io_oled.o_b|= ((pix >> 5) & 0x03f)<< 8;
sys->io_oled.o_b|= ((pix ) & 0x01f)<< 1;
 
// Make certain we had finished with the port (should've ...)
// Make certain we had finished with the port (we should've by now)
while(sys->io_oled.o_ctrl & OLED_BUSY)
;
 
// and send our new command
// and send our new command. Note that o_a and o_b were already set
// ahead of time, and are only now being sent together with this
// command.
sys->io_oled.o_ctrl = ctrl;
 
// To be nice to whatever routine follows, we'll wait 'til the port
161,7 → 260,20
;
}
 
 
/*
* entry()
*
* In all (current) ZipCPU programs, the programs start with an entry()
* function that takes no arguments. The actual bootup entry can be found
* in the bootstram directory, but that calls us here.
*
*/
void entry(void) {
 
// Since we'll be returning to userspace via zip_rtu() in order to
// wait for an interrupt, let's at least place a valid program into
// userspace to run: the idle_task.
unsigned user_regs[16];
for(int i=0; i<15; i++)
user_regs[i] = 0;
168,15 → 280,24
user_regs[15] = (unsigned int)idle_task;
zip_restore_context(user_regs);
 
// Clear the PIC. We'll come back and use it later.
// Clear the PIC. We'll come back and use it later. We clear it here
// partly in order to avoid a race condition later.
zip->pic = CLEARPIC;
 
if (0) { // Wait till we've had power for at least a quarter second
// Wait till we've had power for at least a quarter second
if (0) {
// While this appears to do the task quite nicely, it leaves
// the master_ce line high within the CPU, and so it generates
// a whole lot of debug information in our Verilator simulation,
// busmaster_tb.
int pwrcount = sys->io_pwrcount;
do {
pwrcount = sys->io_pwrcount;
} while((pwrcount>0)&&(pwrcount < CLOCKFREQ_HZ/4));
} else {
// By using the timer and sleeping instead, the simulator can
// be made to run a *lot* faster, with a *lot* less debugging
// ... junk.
int pwrcount = sys->io_pwrcount;
if ((pwrcount > 0)&&(pwrcount < CLOCKFREQ_HZ/4)) {
pwrcount = CLOCKFREQ_HZ/4 - pwrcount;
230,36 → 351,29
oled_init();
 
// 4. Clear screen
// sys->io_oled.o_ctrl = OLED_CLEAR_SCREEN;
// 5. Apply voltage
// 6. Turn on display
// 7. Wait 100ms
// We already stuffed this command sequence into the oled_init,
// so we're good here.
 
// Wait for the command to complete
while(sys->io_oled.o_ctrl & OLED_BUSY)
;
 
// 5. Apply power to VCCEN
sys->io_oled.o_data = OLED_FULLPOWER;
// 6. Delay 100ms
timer_delay(CLOCKFREQ_HZ/10);
 
while(1) {
// 7. Send Display On command
// sys->io_oled.o_ctrl = OLED_CLEAR_SCREEN; // ?? What command is this?
sys->io_ledctrl = 0x0ff;
sys->io_ledctrl = 0x0f0;
 
sys->io_oled.o_ctrl = OLED_DISPLAYON;
 
oled_clear();
 
// Let's start our writes at the top left of the GDDRAM
// (screen memory)
while(sys->io_oled.o_ctrl & OLED_BUSY)
;
sys->io_oled.o_ctrl = 0x2015005f;
sys->io_oled.o_ctrl = 0x2015005f; // Sets column min/max address
 
while(sys->io_oled.o_ctrl & OLED_BUSY)
;
sys->io_oled.o_ctrl = 0x2075003f;
sys->io_oled.o_ctrl = 0x2075003f; // Sets row min/max address
 
sys->io_ledctrl = 0x0fe;
// Now ... finally ... we can send our image.
for(int i=0; i<6144; i++) {
while(sys->io_oled.o_ctrl & OLED_BUSY)
266,14 → 380,22
;
sys->io_oled.o_data = splash[i];
}
sys->io_ledctrl = 0x0fc;
 
// Wait 25 seconds. The LEDs are for a fun effect.
sys->io_ledctrl = 0x0f1;
timer_delay(CLOCKFREQ_HZ*5);
sys->io_ledctrl = 0x0f3;
timer_delay(CLOCKFREQ_HZ*5);
sys->io_ledctrl = 0x0f7;
timer_delay(CLOCKFREQ_HZ*5);
sys->io_ledctrl = 0x0ff;
timer_delay(CLOCKFREQ_HZ*5);
sys->io_ledctrl = 0x0fe;
timer_delay(CLOCKFREQ_HZ*5);
 
 
// Display a second image.
sys->io_ledctrl = 0x0fc;
for(int i=0; i<6144; i++) {
while(sys->io_oled.o_ctrl & OLED_BUSY)
;
280,10 → 402,12
sys->io_oled.o_data = mug[i];
}
 
sys->io_ledctrl = 0x0f0;
// Leave this one in effect for 5 seconds only.
sys->io_ledctrl = 0x0f8;
timer_delay(CLOCKFREQ_HZ*5);
}
 
// We'll never get here, so this line is really just for form.
zip_halt();
}
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.