|
nedoPC.orgElectronics hobbyists community established in 2002 |
|
Плата центрального недопроцессора nedoCPU-32
Author |
Message |
Shaos
Admin
Joined: 08 Jan 2003 23:22 Posts: 22811 Location: Silicon Valley
|
т.е. по сути тут мы имеем 32 цвета, которые процессор современного телевизора умеет смешивать, если они попадаются в соседних строках - в результате получается 16x16=256 цветов (часть из которых повторяется, но не суть) - вот исходник генератора полной таблички цветов и фотка: исходник тут | | | | Code: /******************************************************************* * Modified by A.A.Shabarshin (March-April 2015) * Optimized, recalculated to 14.31818 MHz and added colors * * Original code was taken from "NTSC TV interface" examples: * http://hackaday.io/project/2032-pic32-oscilloscope * Bruce Land Cornell University * June 2014 * "This code uses many cool ideas from * Programming 32-bit Microcontrollers in C: Exploring the PIC32 * by Lucio Di Jasio" * * Uses two Compare units from one timer to do sync and video timing *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * * VIDEO is PortA.1 * SYNC is PortB.1 * */
#include <plib.h> #include <xc.h> // need for pps #include <stdio.h> #include <stdlib.h>
#define NOBACKGROUND #define NOFONT
#if 0 #define SYS_FREQ 60000000 // 8MHZ 4MHz 60MHz 30 <-----<--- 60MHz #pragma config FNOSC = FRCPLL, POSCMOD = OFF, FPLLIDIV = DIV_2, FPLLMUL = MUL_15, FPBDIV = DIV_2, FPLLODIV = DIV_1 #else #define SYS_FREQ 57272720 // 14.31818MHZ 3.579545MHz 57.27272MHz 28.63636 <-----<--- 57.27272MHz #pragma config FNOSC = PRIPLL, POSCMOD = HS, FPLLIDIV = DIV_4, FPLLMUL = MUL_16, FPBDIV = DIV_2, FPLLODIV = DIV_1 #endif #pragma config FWDTEN = OFF #pragma config FSOSCEN = OFF, JTAGEN = OFF
#define PITCH 23 #define OFFSET 96 #define TOFFSET (OFFSET/8) #define DX (OFFSET+640) #define DY (200) #define SCREENSZ (DX*DY/32) int screen_buffer[SCREENSZ] ; volatile int *screen_buffer_addr = screen_buffer ; volatile int *screen_ptr ;
// The DMA channels #define DMAchn1 1 #define DMApri0 0
// video timing #define line_cycles 1818 // 63.5 uSec at 28.6 MHz Fpb, prescaler=1 #define line_offset 159 // offset to start video screen #define us_5_cycles 135 // 5 uSec at 28.6 MHz Fpb, prescaler=1
// video active lines -- 200 total #define image_start 20 #define image_end (image_start+DY) #define top 0 #define left 0 #define right 639 #define bottom 199
// Current line number which is modified // by a state machine in the timer2 ISR volatile int LineCount = 0 ; // ISR driven 1/60 second time volatile int time_tick_60_hz = 0 ; // ISR driven seconds counter volatile int time_seconds = 0; // Absolute frame counter volatile unsigned long time_frames = 0;
#ifndef NOFONT #include "nedofont.h" #endif #ifndef NOBACKGROUND #include "cgatrick.xbm" #endif
#define WAIT 180 // wait 3 seconds before starting video
// == OC3 ISR ============================================ // VECTOR 14 is OC3 vector -- set up of ipl3 in main // vector names from int_1xx_2xx.h void __ISR(14, ipl3) OC3Handler(void) // 14 { if(time_frames>WAIT){ // mPORTBSetBits(BIT_1); // Convert DMA to SPI control DmaChnSetEventControl(DMAchn1, DMA_EV_START_IRQ(_SPI1_TX_IRQ)); // //DmaChnEnable(DMAchn1); // clear the timer interrupt flag -- name from // http://people.ece.cornell.edu/land/courses/ece4760/PIC32/Microchip_stuff/32-bit-Peripheral-Library-Guide.pdf // Table 8.2 mOC3ClearIntFlag(); // mPORTBClearBits(BIT_1); // for profiling the ISR execution time } }
volatile short sound[]={ 750,785,821,856,891,926,961,995,1028,1061,1093,1124,1155,1185,1213,1241, 1267,1292,1316,1339,1360,1380,1399,1416,1432,1446,1458,1469,1478,1486,1492,1496, 1499,1499,1499,1496,1492,1486,1478,1469,1458,1446,1432,1416,1399,1380,1360,1339, 1316,1292,1267,1241,1213,1185,1155,1125,1093,1061,1028,995,961,926,891,856, 821,785,750,714,678,643,608,573,538,504,471,438,406,375,344,314, 286,258,232,207,183,160,139,119,100,83,67,53,41,30,21,13, 7,3,0,0,0,3,7,13,21,30,41,53,67,83,100,119, 139,160,183,207,232,258,286,314,344,374,406,438,471,504,538,573, 608,643,678,714,749,785,821,856,891,926,961,995,1028,1061,1093,1124, 1155,1185,1213,1241,1267,1292,1316,1339,1360,1380,1399,1416,1432,1446,1458,1469, 1478,1486,1492,1496,1499,1499,1499,1496,1492,1486,1478,1469,1458,1446,1432,1416, 1399,1380,1360,1339,1316,1292,1267,1241,1213,1185,1155,1125,1093,1061,1028,995, 961,926,891,856,821,785,750,714,678,643,608,573,538,504,471,438, 406,375,344,314,286,258,232,207,183,160,139,119,100,83,67,53, 41,30,21,13,7,3,0,0,0,3,7,13,21,30,41,53, 67,83,100,119,139,160,183,207,232,258,286,314,344,374,406,438, 471,504,538,573,608,643,678,714 };
// == Timer 2 ISR ========================================= void __ISR(_TIMER_2_VECTOR, ipl2) Timer2Handler(void) { //mPORTBSetBits(BIT_1); // for profiling the ISR execution time // update the current scanline number LineCount++ ; /* // OpenOC5(OC_ON | OC_TIMER2_SRC | OC_CONTINUE_PULSE, line_offset+18+sound[LineCount], line_offset+12); if(LineCount >= image_start + 20 && LineCount < image_end - 100) OpenOC5(OC_ON | OC_TIMER2_SRC | OC_SINGLE_PULSE, line_offset+300, line_offset+200); else CloseOC5(); */ // start the DMA byte blaster to the screen if (LineCount >= image_start && LineCount < image_end){ if(time_frames>WAIT){ // set the Chan1 DMA transfer parameters: source & destination address, // source & destination size, number of bytes per event // 32 bytes / line with 4 bytes per transfer (SPI in 32 bit mode) //screen_ptr = screen_buffer + ((LineCount - image_start)<<5) ; DmaChnSetTxfer(DMAchn1, (void*)screen_ptr, (void*)&SPI1BUF, 92, 4, 4); // IRO 17 is the output compare 3 interrupt (See datasheet table 7.1) DmaChnSetEventControl(DMAchn1, DMA_EV_START_IRQ(17)); // // turn it on for 32 bytes DmaChnEnable(DMAchn1); } // increment the image memory pointer for the next ISR pass screen_ptr += PITCH; // PITCH 32-bit words per line } // update the frame time_tick immediately after image is copied else if(LineCount==image_end) { // a general propose time base if((++time_tick_60_hz%60)==0) time_seconds++; } // == SYNC state machine ==== // begin long (Vertical) synch after line 247 else if (LineCount==248) {OC2R = line_cycles - us_5_cycles ;} // back to regular sync after line 250 // the first condition eliminates sync for one line (to avoid duplicate) else if (LineCount==250) {OC2R = 0 ;} else if (LineCount==251) {OC2R = us_5_cycles ;} // start new frame after line 262 and reset the image memory pointer else if (LineCount==263) { LineCount = 1; // reset for the next frame screen_ptr = screen_buffer_addr; time_frames++; } // clear the timer interrupt flag mT2ClearIntFlag(); //mPORTBClearBits(BIT_1); // for profiling the ISR execution time }
//== plot a point ========================================================= //plot one point //at x,y with color 1=white 0=black 2=invert void video_pt(int x, int y, char c) { //calculate i based upon this and x,y // the word with the pixel in it //int i = (x/32) + y*PITCH x += OFFSET; if (c==1) screen_buffer[(x >> 5) + (y * PITCH)] |= 1<<(31-(x & 0x1f)); else if (c==0) screen_buffer[(x >> 5) + (y * PITCH)] &= ~(1<<(31-(x & 0x1f))); else // c==2 screen_buffer[(x >> 5) + (y * PITCH)] ^= 1<<(31-(x & 0x1f)); }
//================================== //plot a line //at x1,y1 to x2,y2 with color 1=white 0=black 2=invert //NOTE: this function requires signed chars //Code is from David Rodgers, //"Procedural Elements of Computer Graphics",1985 void video_line(int x1, int y1, int x2, int y2, char c) { int e; signed int dx,dy,j, temp; signed char s1,s2, xchange; signed int x,y;
x = x1; y = y1;
//take absolute value if (x2 < x1) { dx = x1 - x2; s1 = -1; }
else if (x2 == x1) { dx = 0; s1 = 0; }
else { dx = x2 - x1; s1 = 1; }
if (y2 < y1) { dy = y1 - y2; s2 = -1; }
else if (y2 == y1) { dy = 0; s2 = 0; }
else { dy = y2 - y1; s2 = 1; }
xchange = 0;
if (dy>dx) { temp = dx; dx = dy; dy = temp; xchange = 1; }
e = ((int)dy<<1) - dx;
for (j=0; j<=dx; j++) { video_pt(x,y,c);
if (e>=0) { if (xchange==1) x = x + s1; else y = y + s2; e = e - ((int)dx<<1); }
if (xchange==1) y = y + s2; else x = x + s1;
e = e + ((int)dy<<1); } }
//================================== //return the value of one point //at x,y with color 1=white 0=black char video_state(int x, int y) { //The following construction detects exactly one bit at the x,y location return (screen_buffer[((x+OFFSET) >> 5) + (y * PITCH)] & (1<<(31-(x & 0x1f))))?1:0 ; }
//================================== // put a big character on the screen // c is index into bitmap void video_putchar(int x, int y, int c) { #ifndef NOFONT x += TOFFSET; int j = (x>>2)+(y<<3)*PITCH; int shf = (3-(x&3))<<3; int msk = ~(255<<shf); unsigned char *ptr = font8x8[c-32]; screen_buffer[j]=(screen_buffer[j] & msk)|(*(ptr++)<<shf);j+=PITCH; screen_buffer[j]=(screen_buffer[j] & msk)|(*(ptr++)<<shf);j+=PITCH; screen_buffer[j]=(screen_buffer[j] & msk)|(*(ptr++)<<shf);j+=PITCH; screen_buffer[j]=(screen_buffer[j] & msk)|(*(ptr++)<<shf);j+=PITCH; screen_buffer[j]=(screen_buffer[j] & msk)|(*(ptr++)<<shf);j+=PITCH; screen_buffer[j]=(screen_buffer[j] & msk)|(*(ptr++)<<shf);j+=PITCH; screen_buffer[j]=(screen_buffer[j] & msk)|(*(ptr++)<<shf);j+=PITCH; screen_buffer[j]=(screen_buffer[j] & msk)|(*ptr<<shf); #endif }
//================================== // put a string of big characters on the screen void video_string(int x, int y, char *str) { char i; for (i=0; str[i]!=0; i++) { video_putchar(x++,y,str[i]); } }
int* xolinedirect(int y){return &screen_buffer[PITCH*y+(OFFSET>>5)];}
// ======================================================================== int main(void) { int* iptr; float f; unsigned short us; unsigned long i,j,n,m,stored,maxstored=0; // global time int time, seconds, x, y, k, c, *p; char time_string[10],str[32];
// Configure the device for maximum performance but do not change the PBDIV // Given the options, this function will change the flash wait states, RAM // wait state and enable prefetch cache but will not change the PBDIV. // The PBDIV value is already set via the pragma FPBDIV option above.. SYSTEMConfig(SYS_FREQ, SYS_CFG_WAIT_STATES | SYS_CFG_PCACHE);
//make sure analog is cleared //ANSELA =0; //ANSELB =0;
// timer interrupt ////////////////////////// // Set up timer2 on, interrupts, internal clock, prescalar 1, toggle rate // 63.5 microSec OpenTimer2(T2_ON | T2_SOURCE_INT | T2_PS_1_1, line_cycles); // set up the timer interrupt with a priority of 2 ConfigIntTimer2(T2_INT_ON | T2_INT_PRIOR_2); mT2ClearIntFlag(); // and clear the interrupt flag
// Compare match setup ////////////////////// //Set up compare match unit to produce sync pulses // 5 uSec low // or 63.5-5 = 58.5 microSec (2340 ticks) low // pulse duration will be controlled in Timer2 ISR // #define OpenOC2( config, value1, value2) ( OC2RS = (value1), OC2R = (value2), OC2CON = (config) ) OpenOC2(OC_ON | OC_TIMER2_SRC | OC_CONTINUE_PULSE, line_cycles-1, us_5_cycles); // OC2 is PPS group 2, map to RPB1 (pin 5) PPSOutput(2, RPB1, OC2);
// OC3 setup ///////////////////////////////// // Compare unit for video timing, // using the interrupt flag to trigger the first DMA, // then use the ISR to change the DMA control to SPI // #define OpenOC2( config, value1, value2) ( OC2RS = (value1), OC2R = (value2), OC2CON = (config) ) // Pulse needs to be TWO cycles long OpenOC3(OC_ON | OC_TIMER2_SRC | OC_CONTINUE_PULSE, line_offset+2, line_offset); // turn on ISR so that DMA can covert to SPI control ConfigIntOC3(OC_INT_PRIOR_1 | OC_INT_ON); //3 // mOC3ClearIntFlag(); // and clear the interrupt flag
// OC4 setup ///////////////////////////////// OpenOC4(OC_ON | OC_TIMER2_SRC | OC_CONTINUE_PULSE, line_offset+40, line_offset+112); // OC4 is PPS group 3, map to RPB13 (pin 24) PPSOutput(3, RPB13, OC4);
// OC5 setup ///////////////////////////////// OpenOC5(OC_ON | OC_TIMER2_SRC | OC_CONTINUE_PULSE, line_cycles-200, line_cycles-100); // OC5 is PPS group 3, map to RPA2 (pin 9) PPSOutput(3, RPA2, OC5); // SPI configure ///////////////////////////// // SCK1 is pin 25 RB14 // SDO1 is PPS group 2, map to RPA1 (pin 3) // SDI1 is PPS group 2, map to RPB8 (pin 17) ??? // SS1 input is PPS group 1, map to RPB7 (pin 16) for framing // specify PPS group, signal, logical pin name PPSInput (1, SS1, RPB7); PPSOutput(2, RPA1, SDO1); // control sync for DAC mPORTBSetPinsDigitalOut(BIT_0|BIT_2|BIT_3); mPORTBSetBits(BIT_0); mPORTBClearBits(BIT_2); mPORTBClearBits(BIT_3);
// divide Fpb by N, configure the I/O ports. 32 bit transfer SpiChnOpen(SPI_CHANNEL1, SPI_OPEN_ON | SPI_OPEN_MODE32 | SPI_OPEN_MSTEN , 2); // N=6
//=== DMA Channel 1 ================================ // Open DMA Chan1 and chain from channel zero DmaChnOpen(DMAchn1, DMApri0, DMA_OPEN_DEFAULT);
// setup system wide interrupts /// INTEnableSystemMultiVectoredInt();
#ifndef NOBACKGROUND iptr = (int*)cgatrick_bits; for(i=0;i<SCREENSZ;i++) { k = iptr[i]; c = 0; n = 1; m = 0x80000000; for(j=0;j<32;j++) { if(!(k&n)) c|=m; n <<= 1; m >>= 1; } screen_buffer[i] = c; } #endif
// generate color burst
p = screen_buffer; for(y=0;y<200;y++) { p[0] = 0x00000CCC; p[1] = 0xCCCCCC00; p += PITCH; }
// generate color chart for(y=0;y<192;y++) { if((y%12)==11) continue; // black lines between colors p = xolinedirect(y+4); j = y/12; for(x=0;x<16;x++) { if(y&1) p[x+4] = (x<<28)|(x<<24)|(x<<20)|(x<<16)|(x<<12)|(x<<8)|(x<<4);//|x; else p[x+4] = (j<<28)|(j<<24)|(j<<20)|(j<<16)|(j<<12)|(j<<8)|(j<<4);//|j; } } #if 1 // Draw the screen boundaries video_line(left,top, right,top, 1); // top video_line(right,top, right,bottom, 1); // right video_line(right,bottom, left,bottom, 1); // bottom video_line(left,top, left,bottom ,1); // left #endif // Draw a title video_string(0,0,"nedoPC-32-A"); seconds = stored = n = x = y = 0; c = 32; k = 0; srand(11111); while(1) { n++; #if 0 // random characters k = rand(); video_putchar(k%80,2+((k>>6)&15),++c); if(c==255) c=31; #endif #if 0 // random lines k = rand(); c = k&511; k=8+((k>>8)%184); video_line(x,y,c,k,2); x = c; y = k; #endif #if 0 // random pixels k = rand(); video_pt(k%640,8+((k>>9)%184),2); #endif if(time != time_tick_60_hz) { time = time_tick_60_hz ; stored = n; if(n>maxstored) maxstored=n; n = 0; if(seconds != time_seconds) { seconds = time_seconds; sprintf(time_string, "%d:%d",seconds,stored); video_string(0, 24, time_string);
if(seconds&1) mPORTBClearBits(BIT_2); else mPORTBSetBits(BIT_2);
if(seconds&2) mPORTBClearBits(BIT_3); else mPORTBSetBits(BIT_3); } } }
}
| | | | |
|
06 Apr 2015 18:22 |
|
|
Shaos
Admin
Joined: 08 Jan 2003 23:22 Posts: 22811 Location: Silicon Valley
|
Вот восстановленные по фотке 32 основных цвета (могут быть большие погрешности): | | | | Code: /* EVEN LINES: */
/* 0000 */ RGB( 0, 0, 0), /* #000000 H=... S=.. V=0 */ /* 0001 */ RGB( 22, 21,187), /* #1615BB H=240 S=89 V=73 */ /* 0010 */ RGB(112, 26, 48), /* #701A30 H=345 S=77 V=44 */ /* 0011 */ RGB(117, 17,197), /* #7511C5 H=273 S=91 V=77 */ /* 0100 */ RGB( 38, 68, 23), /* #264417 H=100 S=66 V=27 */ /* 0101 */ RGB( 76, 65, 72), /* #4C4148 H=... S=.. V=30 */ /* 0110 */ RGB(136, 50, 15), /* #88320F H=17 S=89 V=53 */ /* 0111 */ RGB(154, 59, 77), /* #9A324D H=344 S=68 V=60 */ /* 1000 */ RGB( 10, 54, 47), /* #0A362F H=170 S=81 V=21 */ /* 1001 */ RGB( 7, 44,195), /* #072CC3 H=228 S=96 V=76 */ /* 1010 */ RGB( 62, 71, 87), /* #3E4757 H=... S=.. V=34 */ /* 1011 */ RGB( 45, 50,182), /* #2D32B6 H=238 S=75 V=71 */ /* 1100 */ RGB( 9,112, 42), /* #09702A H=139 S=92 V=44 */ /* 1101 */ RGB( 14,112,113), /* #0E7071 H=181 S=88 V=44 */ /* 1110 */ RGB( 55,109, 33), /* #376D21 H=103 S=70 V=43 */ /* 1111 */ RGB(110,113,121), /* #6E7179 H=... S=.. V=47 */
/* ODD LINES: */
/* 0000 */ RGB( 0, 0, 0), /* #000000 H=... S=.. V=0 */ /* 0001 */ RGB( 12,115, 37), /* #0C7325 H=135 S=90 V=45 */ /* 0010 */ RGB( 7, 58,178), /* #073AB2 H=222 S=96 V=70 */ /* 0011 */ RGB( 10,135,107), /* #0A876B H=167 S=93 V=53 */ /* 0100 */ RGB( 85, 31,131), /* #551F83 H=272 S=76 V=51 */ /* 0101 */ RGB( 95, 80, 84), /* #5F5054 H=... S=.. V=37 */ /* 0110 */ RGB( 28, 41,222), /* #1C29DE H=236 S=87 V=87 */ /* 0111 */ RGB( 44,104,167), /* #2C68A7 H=211 S=74 V=65 */ /* 1000 */ RGB(115, 37, 19), /* #732513 H=11 S=83 V=45 */ /* 1001 */ RGB(105,107, 38), /* #696B26 H=62 S=64 V=42 */ /* 1010 */ RGB( 96, 79, 77), /* #604F4D H=... S=.. V=38 */ /* 1011 */ RGB( 70,151, 56), /* #469738 H=111 S=63 V=59 */ /* 1100 */ RGB(182, 33,105), /* #B62169 H=331 S=82 V=71 */ /* 1101 */ RGB(173, 93, 62), /* #AD5D3E H=17 S=64 V=68 */ /* 1110 */ RGB(142, 72,179), /* #8E48B3 H=279 S=60 V=70 */ /* 1111 */ RGB(153,136,119), /* #998877 H=... S=.. V=60 */
| | | | |
H - это Hue, который можно воспринимать как угол фазы (правда в GIMP он меньше фазы NTSC на 120 градусов), которых на удивление много разных (для бесцветных серо-белых тонов H указывать не стал): 000-009 градусов: 0 010-019 градусов: 3 - E0110, O1000, O1101 020-029 градусов: 0 030-039 градусов: 0 040-049 градусов: 0 050-059 градусов: 0 060-069 градусов: 1 - O1001 070-079 градусов: 0 080-089 градусов: 0 090-099 градусов: 0 100-109 градусов: 2 - E0100, E1110 110-119 градусов: 1 - O1011 120-129 градусов: 0 130-139 градусов: 1 - E1100, O0001 140-149 градусов: 0 150-159 градусов: 0 160-169 градусов: 1 - O0011 170-179 градусов: 1 - E1000 180-189 градусов: 1 - E1101 190-199 градусов: 0 200-209 градусов: 0 210-219 градусов: 1 - O0111 220-229 градусов: 2 - E1001, O0010 230-239 градусов: 2 - E1011, O0110 240-249 градусов: 1 - E0001 250-259 градусов: 0 260-269 градусов: 0 270-279 градусов: 1 - E0011, O0100, O1110 280-289 градусов: 0 290-299 градусов: 0 300-309 градусов: 0 310-319 градусов: 0 320-329 градусов: 0 330-339 градусов: 1 - O1100 340-349 градусов: 2 - E0010, E0111 350-359 градусов: 0 Отсюда видно, что разница между чётными и нечётными строками составляет полторы четвертушки, или примерно 135 градусов... P.S. DOOM в этой новой 256-цветной палитре и размером 160x100 будет выглядеть так:
|
06 Apr 2015 23:13 |
|
|
Shaos
Admin
Joined: 08 Jan 2003 23:22 Posts: 22811 Location: Silicon Valley
|
Я понял в чём проблема - я неправильно выбрал длину строки - надо заменить 1818 на 1820 и тогда строка будет составлять 227.5 циклов основной частоты цвета - как и положено по стандарту NTSC (тогда чётные и нечётные строки будут отличаться на 180 градусов, а не на 135) P.S. Сделал 1820 циклов основной частоты в строке и цвет ИСЧЕЗ!!! Никакие дальнейшие мухляжи с color-burst-ом не помогли - видимо неточность длины строки играла какую-то немаловажную роль (что значит, что я случайно угадал с первоначальным числом)...
|
07 Apr 2015 16:31 |
|
|
JeNNeR
Fanat
Joined: 18 Nov 2014 09:17 Posts: 52 Location: Отсюда
|
А возврат к предыдущим настройкам возвратил цвет? потому что вполне может быть, что пошел дымок гденть внутри телевизора, и это отразилось как исчезновение цвета... ???
|
07 Apr 2015 22:33 |
|
|
Shaos
Admin
Joined: 08 Jan 2003 23:22 Posts: 22811 Location: Silicon Valley
|
исходник тут | | | | Code: /******************************************************************* * Modified by A.A.Shabarshin (March-April 2015) * Optimized, recalculated to 14.31818 MHz and added colors * * Original code was taken from "NTSC TV interface" examples: * http://hackaday.io/project/2032-pic32-oscilloscope * Bruce Land Cornell University * June 2014 * "This code uses many cool ideas from * Programming 32-bit Microcontrollers in C: Exploring the PIC32 * by Lucio Di Jasio" * * Uses two Compare units from one timer to do sync and video timing *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * * VIDEO is PortA.1 * SYNC is PortB.1 * */
#include <plib.h> #include <xc.h> // need for pps #include <stdio.h> #include <stdlib.h>
#define NOBACKGROUND #define NOFONT
#if 0 #define SYS_FREQ 60000000 // 8MHZ 4MHz 60MHz 30 <-----<--- 60MHz #pragma config FNOSC = FRCPLL, POSCMOD = OFF, FPLLIDIV = DIV_2, FPLLMUL = MUL_15, FPBDIV = DIV_2, FPLLODIV = DIV_1 #else #define SYS_FREQ 57272720 // 14.31818MHZ 3.579545MHz 57.27272MHz 28.63636 <-----<--- 57.27272MHz #pragma config FNOSC = PRIPLL, POSCMOD = HS, FPLLIDIV = DIV_4, FPLLMUL = MUL_16, FPBDIV = DIV_2, FPLLODIV = DIV_1 #endif #pragma config FWDTEN = OFF #pragma config FSOSCEN = OFF, JTAGEN = OFF
#define PITCH 23 #define OFFSET 96 #define TOFFSET (OFFSET/8) #define DX (OFFSET+640) #define DY (200) #define SCREENSZ (DX*DY/32) int screen_buffer[SCREENSZ] ; volatile int *screen_buffer_addr = screen_buffer ; volatile int *screen_ptr ;
// The DMA channels #define DMAchn1 1 #define DMApri0 0
// video timing #define line_cycles 1823 // 63.5 uSec at 28.6 MHz Fpb (it must be 227.5 cycles of subcarrier freq) #define line_offset 168 // offset to start video screen (with color burst for color mode) #define us_5_cycles 135 // 4.7 uSec at 28.6 MHz Fpb, prescaler=1
// video active lines -- 200 total #define image_start 20 #define image_end (image_start+DY) #define top 0 #define left 0 #define right 639 #define bottom 199
// Current line number which is modified // by a state machine in the timer2 ISR volatile int LineCount = 0 ; // ISR driven 1/60 second time volatile int time_tick_60_hz = 0 ; // ISR driven seconds counter volatile int time_seconds = 0; // Absolute frame counter volatile unsigned long time_frames = 0;
#ifndef NOFONT #include "nedofont.h" #endif #ifndef NOBACKGROUND #include "cgatrick.xbm" #endif
#define WAIT 180 // wait 3 seconds before starting video
// == OC3 ISR ============================================ // VECTOR 14 is OC3 vector -- set up of ipl3 in main // vector names from int_1xx_2xx.h void __ISR(14, ipl3) OC3Handler(void) // 14 { if(time_frames>WAIT){ // mPORTBSetBits(BIT_1); // Convert DMA to SPI control DmaChnSetEventControl(DMAchn1, DMA_EV_START_IRQ(_SPI1_TX_IRQ)); // //DmaChnEnable(DMAchn1); // clear the timer interrupt flag -- name from // http://people.ece.cornell.edu/land/courses/ece4760/PIC32/Microchip_stuff/32-bit-Peripheral-Library-Guide.pdf // Table 8.2 mOC3ClearIntFlag(); // mPORTBClearBits(BIT_1); // for profiling the ISR execution time } }
volatile short sound[]={ 750,785,821,856,891,926,961,995,1028,1061,1093,1124,1155,1185,1213,1241, 1267,1292,1316,1339,1360,1380,1399,1416,1432,1446,1458,1469,1478,1486,1492,1496, 1499,1499,1499,1496,1492,1486,1478,1469,1458,1446,1432,1416,1399,1380,1360,1339, 1316,1292,1267,1241,1213,1185,1155,1125,1093,1061,1028,995,961,926,891,856, 821,785,750,714,678,643,608,573,538,504,471,438,406,375,344,314, 286,258,232,207,183,160,139,119,100,83,67,53,41,30,21,13, 7,3,0,0,0,3,7,13,21,30,41,53,67,83,100,119, 139,160,183,207,232,258,286,314,344,374,406,438,471,504,538,573, 608,643,678,714,749,785,821,856,891,926,961,995,1028,1061,1093,1124, 1155,1185,1213,1241,1267,1292,1316,1339,1360,1380,1399,1416,1432,1446,1458,1469, 1478,1486,1492,1496,1499,1499,1499,1496,1492,1486,1478,1469,1458,1446,1432,1416, 1399,1380,1360,1339,1316,1292,1267,1241,1213,1185,1155,1125,1093,1061,1028,995, 961,926,891,856,821,785,750,714,678,643,608,573,538,504,471,438, 406,375,344,314,286,258,232,207,183,160,139,119,100,83,67,53, 41,30,21,13,7,3,0,0,0,3,7,13,21,30,41,53, 67,83,100,119,139,160,183,207,232,258,286,314,344,374,406,438, 471,504,538,573,608,643,678,714 };
// == Timer 2 ISR ========================================= void __ISR(_TIMER_2_VECTOR, ipl2) Timer2Handler(void) { //mPORTBSetBits(BIT_1); // for profiling the ISR execution time // update the current scanline number LineCount++ ; /* // OpenOC5(OC_ON | OC_TIMER2_SRC | OC_CONTINUE_PULSE, line_offset+18+sound[LineCount], line_offset+12); if(LineCount >= image_start + 20 && LineCount < image_end - 100) OpenOC5(OC_ON | OC_TIMER2_SRC | OC_SINGLE_PULSE, line_offset+300, line_offset+200); else CloseOC5(); */ // start the DMA byte blaster to the screen if (LineCount >= image_start && LineCount < image_end){ if(time_frames>WAIT){ // set the Chan1 DMA transfer parameters: source & destination address, // source & destination size, number of bytes per event // 32 bytes / line with 4 bytes per transfer (SPI in 32 bit mode) //screen_ptr = screen_buffer + ((LineCount - image_start)<<5) ; DmaChnSetTxfer(DMAchn1, (void*)screen_ptr, (void*)&SPI1BUF, 92, 4, 4); // IRO 17 is the output compare 3 interrupt (See datasheet table 7.1) DmaChnSetEventControl(DMAchn1, DMA_EV_START_IRQ(17)); // // turn it on for 32 bytes DmaChnEnable(DMAchn1); } // increment the image memory pointer for the next ISR pass screen_ptr += PITCH; // PITCH 32-bit words per line } // update the frame time_tick immediately after image is copied else if(LineCount==image_end) { // a general propose time base if((++time_tick_60_hz%60)==0) time_seconds++; } // == SYNC state machine ==== // begin long (Vertical) synch after line 247 else if (LineCount==248) {OC2R = line_cycles - us_5_cycles ;} // back to regular sync after line 250 // the first condition eliminates sync for one line (to avoid duplicate) else if (LineCount==250) {OC2R = 0 ;} else if (LineCount==251) {OC2R = us_5_cycles ;} // start new frame after line 262 and reset the image memory pointer else if (LineCount==263) { LineCount = 1; // reset for the next frame screen_ptr = screen_buffer_addr; // increment frame counter ++time_frames; } // clear the timer interrupt flag mT2ClearIntFlag(); //mPORTBClearBits(BIT_1); // for profiling the ISR execution time }
//== plot a point ========================================================= //plot one point //at x,y with color 1=white 0=black 2=invert void video_pt(int x, int y, char c) { //calculate i based upon this and x,y // the word with the pixel in it //int i = (x/32) + y*PITCH x += OFFSET; if (c==1) screen_buffer[(x >> 5) + (y * PITCH)] |= 1<<(31-(x & 0x1f)); else if (c==0) screen_buffer[(x >> 5) + (y * PITCH)] &= ~(1<<(31-(x & 0x1f))); else // c==2 screen_buffer[(x >> 5) + (y * PITCH)] ^= 1<<(31-(x & 0x1f)); }
//================================== //plot a line //at x1,y1 to x2,y2 with color 1=white 0=black 2=invert //NOTE: this function requires signed chars //Code is from David Rodgers, //"Procedural Elements of Computer Graphics",1985 void video_line(int x1, int y1, int x2, int y2, char c) { int e; signed int dx,dy,j, temp; signed char s1,s2, xchange; signed int x,y;
x = x1; y = y1;
//take absolute value if (x2 < x1) { dx = x1 - x2; s1 = -1; }
else if (x2 == x1) { dx = 0; s1 = 0; }
else { dx = x2 - x1; s1 = 1; }
if (y2 < y1) { dy = y1 - y2; s2 = -1; }
else if (y2 == y1) { dy = 0; s2 = 0; }
else { dy = y2 - y1; s2 = 1; }
xchange = 0;
if (dy>dx) { temp = dx; dx = dy; dy = temp; xchange = 1; }
e = ((int)dy<<1) - dx;
for (j=0; j<=dx; j++) { video_pt(x,y,c);
if (e>=0) { if (xchange==1) x = x + s1; else y = y + s2; e = e - ((int)dx<<1); }
if (xchange==1) y = y + s2; else x = x + s1;
e = e + ((int)dy<<1); } }
//================================== //return the value of one point //at x,y with color 1=white 0=black char video_state(int x, int y) { //The following construction detects exactly one bit at the x,y location return (screen_buffer[((x+OFFSET) >> 5) + (y * PITCH)] & (1<<(31-(x & 0x1f))))?1:0 ; }
//================================== // put a big character on the screen // c is index into bitmap void video_putchar(int x, int y, int c) { #ifndef NOFONT x += TOFFSET; int j = (x>>2)+(y<<3)*PITCH; int shf = (3-(x&3))<<3; int msk = ~(255<<shf); unsigned char *ptr = font8x8[c-32]; screen_buffer[j]=(screen_buffer[j] & msk)|(*(ptr++)<<shf);j+=PITCH; screen_buffer[j]=(screen_buffer[j] & msk)|(*(ptr++)<<shf);j+=PITCH; screen_buffer[j]=(screen_buffer[j] & msk)|(*(ptr++)<<shf);j+=PITCH; screen_buffer[j]=(screen_buffer[j] & msk)|(*(ptr++)<<shf);j+=PITCH; screen_buffer[j]=(screen_buffer[j] & msk)|(*(ptr++)<<shf);j+=PITCH; screen_buffer[j]=(screen_buffer[j] & msk)|(*(ptr++)<<shf);j+=PITCH; screen_buffer[j]=(screen_buffer[j] & msk)|(*(ptr++)<<shf);j+=PITCH; screen_buffer[j]=(screen_buffer[j] & msk)|(*ptr<<shf); #endif }
//================================== // put a string of big characters on the screen void video_string(int x, int y, char *str) { char i; for (i=0; str[i]!=0; i++) { video_putchar(x++,y,str[i]); } }
void color_burst(char c) { int y,*p = screen_buffer; for(y=0;y<200;y++) { p[0] = (c<<28)|(c<<24)|(c<<20)|(c<<16)|(c<<12)|(c<<8)|(c<<4)|c; p[1] = (c<<28); p += PITCH; } }
int* xolinedirect(int y){return &screen_buffer[PITCH*y+(OFFSET>>5)];}
// ======================================================================== int main(void) { int* iptr; float f; unsigned short us; unsigned long i,j,n,m,stored,maxstored=0; // global time int time, seconds, x, y, k, c, *p; char time_string[10],str[32];
// Configure the device for maximum performance but do not change the PBDIV // Given the options, this function will change the flash wait states, RAM // wait state and enable prefetch cache but will not change the PBDIV. // The PBDIV value is already set via the pragma FPBDIV option above.. SYSTEMConfig(SYS_FREQ, SYS_CFG_WAIT_STATES | SYS_CFG_PCACHE);
//make sure analog is cleared //ANSELA =0; //ANSELB =0;
// timer interrupt ////////////////////////// // Set up timer2 on, interrupts, internal clock, prescalar 1, toggle rate // 63.5 microSec OpenTimer2(T2_ON | T2_SOURCE_INT | T2_PS_1_1, line_cycles); // set up the timer interrupt with a priority of 2 ConfigIntTimer2(T2_INT_ON | T2_INT_PRIOR_2); mT2ClearIntFlag(); // and clear the interrupt flag
// Compare match setup ////////////////////// //Set up compare match unit to produce sync pulses // 5 uSec low // or 63.5-5 = 58.5 microSec (2340 ticks) low // pulse duration will be controlled in Timer2 ISR // #define OpenOC2( config, value1, value2) ( OC2RS = (value1), OC2R = (value2), OC2CON = (config) ) OpenOC2(OC_ON | OC_TIMER2_SRC | OC_CONTINUE_PULSE, line_cycles-1, us_5_cycles); // OC2 is PPS group 2, map to RPB1 (pin 5) PPSOutput(2, RPB1, OC2);
// OC3 setup ///////////////////////////////// // Compare unit for video timing, // using the interrupt flag to trigger the first DMA, // then use the ISR to change the DMA control to SPI // #define OpenOC2( config, value1, value2) ( OC2RS = (value1), OC2R = (value2), OC2CON = (config) ) // Pulse needs to be TWO cycles long OpenOC3(OC_ON | OC_TIMER2_SRC | OC_CONTINUE_PULSE, line_offset+2, line_offset); // turn on ISR so that DMA can covert to SPI control ConfigIntOC3(OC_INT_PRIOR_1 | OC_INT_ON); //3 // mOC3ClearIntFlag(); // and clear the interrupt flag
// OC4 setup ///////////////////////////////// OpenOC4(OC_ON | OC_TIMER2_SRC | OC_CONTINUE_PULSE, line_offset+0, line_offset+72); // OC4 is PPS group 3, map to RPB13 (pin 24) PPSOutput(3, RPB13, OC4);
// OC5 setup ///////////////////////////////// OpenOC5(OC_ON | OC_TIMER2_SRC | OC_CONTINUE_PULSE, line_cycles-200, line_cycles-100); // OC5 is PPS group 3, map to RPA2 (pin 9) PPSOutput(3, RPA2, OC5); // SPI configure ///////////////////////////// // SCK1 is pin 25 RB14 // SDO1 is PPS group 2, map to RPA1 (pin 3) // SDI1 is PPS group 2, map to RPB8 (pin 17) ??? // SS1 input is PPS group 1, map to RPB7 (pin 16) for framing // specify PPS group, signal, logical pin name PPSInput (1, SS1, RPB7); PPSOutput(2, RPA1, SDO1); // control sync for DAC mPORTBSetPinsDigitalOut(BIT_0|BIT_2|BIT_3); mPORTBSetBits(BIT_0); mPORTBClearBits(BIT_2); mPORTBClearBits(BIT_3);
// divide Fpb by N, configure the I/O ports. 32 bit transfer SpiChnOpen(SPI_CHANNEL1, SPI_OPEN_ON | SPI_OPEN_MODE32 | SPI_OPEN_MSTEN , 2); // N=6
//=== DMA Channel 1 ================================ // Open DMA Chan1 and chain from channel zero DmaChnOpen(DMAchn1, DMApri0, DMA_OPEN_DEFAULT);
// setup system wide interrupts /// INTEnableSystemMultiVectoredInt();
#ifndef NOBACKGROUND iptr = (int*)cgatrick_bits; for(i=0;i<SCREENSZ;i++) { k = iptr[i]; c = 0; n = 1; m = 0x80000000; for(j=0;j<32;j++) { if(!(k&n)) c|=m; n <<= 1; m >>= 1; } screen_buffer[i] = c; } #endif
memset(screen_buffer,0,sizeof(screen_buffer)); color_burst(0xC);
// generate color chart #if 0 for(y=0;y<192;y++) { if((y%12)==11) continue; // black lines between colors p = xolinedirect(y+4); j = y/12; for(x=0;x<16;x++) { if(y&1) p[x+2] = (x<<28)|(x<<24)|(x<<20)|(x<<16)|(x<<12)|(x<<8)|(x<<4);//|x; else p[x+2] = (j<<28)|(j<<24)|(j<<20)|(j<<16)|(j<<12)|(j<<8)|(j<<4);//|j; } } #else for(y=0;y<200;y++) { p = xolinedirect(y); p[0] = 0x00000000; p[1] = 0x00111111; p[2] = 0x11112222; p[3] = 0x22222233; p[4] = 0x33333333; p[5] = 0x44444444; p[6] = 0x44555555; p[7] = 0x55556666; p[8] = 0x66666677; p[9] = 0x77777777; p[10] = 0x88888888; p[11] = 0x88999999; p[12] = 0x9999AAAA; p[13] = 0xAAAAAABB; p[14] = 0xBBBBBBBB; p[15] = 0xCCCCCCCC; p[16] = 0xCCDDDDDD; p[17] = 0xDDDDEEEE; p[18] = 0xEEEEEEFF; p[19] = 0xFFFFFFFF; }
#endif #if 1 // Draw the screen boundaries video_line(left,top, right,top, 1); // top video_line(right,top, right,bottom, 1); // right video_line(right-1,top, right-1,bottom, 1); // right video_line(right,bottom, left,bottom, 1); // bottom video_line(left,top, left,bottom ,1); // left video_line(left+1,top, left+1,bottom ,1); // left #endif // Draw a title video_string(0,0,"nedoPC-32-A"); seconds = stored = n = x = y = 0; c = 32; k = 0; srand(11111); while(1) { n++; #if 0 // random characters k = rand(); video_putchar(k%80,2+((k>>6)&15),++c); if(c==255) c=31; #endif #if 0 // random lines k = rand(); c = k&511; k=8+((k>>8)%184); video_line(x,y,c,k,2); x = c; y = k; #endif #if 0 // random pixels k = rand(); video_pt(k%640,8+((k>>9)%184),2); #endif if(time != time_tick_60_hz) { time = time_tick_60_hz ; stored = n; if(n>maxstored) maxstored=n; n = 0; if(seconds != time_seconds) { seconds = time_seconds; sprintf(time_string, "%d:%d",seconds,stored); video_string(0, 24, time_string);
if(seconds&1) mPORTBClearBits(BIT_2); else mPORTBSetBits(BIT_2);
if(seconds&2) mPORTBClearBits(BIT_3); else mPORTBSetBits(BIT_3); } } }
}
| | | | |
Методом научного тыка подобрал такую длину строки, при которой цвет не только появился, но и стал одинаковым для чётных и нечётных строк - и это число как ни странно 1823 (при этом правда у нас остаётся только 16 цветов, зато они без дырок)! P.S. Цвет даже появился на "старом" цветном NTSC с электронно-лучевой трубкой (последний CRT TV системы NTSC, выпущенный в 2005 году под маркой "Sony Trinitron"), в отличие от всех предыдущих вариантов, когда цвет на нём не ловился - правда там есть какие-то мерцания, но я надеюсь их убрать путём аккуратного подбора резисторов (фотки с него не снимал - все нижеприведённые фотки сняты c SONY LCD TV)... P.P.S. Надо попробовать color-burst подвигать, чтобы получить цвета, аналогичные CGA-composite - это будет кул
|
08 Apr 2015 06:09 |
|
|
Shaos
Admin
Joined: 08 Jan 2003 23:22 Posts: 22811 Location: Silicon Valley
|
Путём сдвига color-burst-a получилось четыре набора цветов (правда там похоже одни и теже цвета перемежаются), причём последний color_burst(0x9) примерно (но не полностью) похож на CGA-трюк: P.S. Интересно, что color_burst(0x3) примерно соответствует Tandy, а color_burst(0x6) - PCjr
|
09 Apr 2015 17:53 |
|
|
Shaos
Admin
Joined: 08 Jan 2003 23:22 Posts: 22811 Location: Silicon Valley
|
Вот ещё картинок с экрана ТВ P.S. причём TRON "широкоформатный"
|
09 Apr 2015 19:07 |
|
|
Shaos
Admin
Joined: 08 Jan 2003 23:22 Posts: 22811 Location: Silicon Valley
|
По умолчанию будет палитра из color_burst(0xC) - назовём её палитра номер 0: Цвета из неё с некоторой натяжкой натягиваются на стандартные 16 цветов CGA/EGA (см. справа в каждой строке). Палитра color_burst(0xC) - 0000 1100 1100 1100... будет палитрой номер 0 (Xorya composite см.выше). Палитра color_burst(0x9) - 0001 1001 1001 1001... будет палитрой номер 1 (CGA composite). Палитра color_burst(0x3) - 0011 0011 0011 0011... будет палитрой номер 2 (Tandy composite). Палитра color_burst(0x6) - 0110 0110 0110 0110... будет палитрой номер 3 (PCjr composite). Как видим фаза color burst сигнала между палитрами увеличивается на 90 градусов (четверть полного оборота). P.S. Это значит, что можно писать код и отлаживаться в DOSBox, который умеет эмулировать color-burst-режимы работы CGA P.P.S. Вот примеры CGA-графики и Tandy-графики с http://nerdlypleasures.blogspot.com/201 ... phics.html
|
09 Apr 2015 19:34 |
|
|
Shaos
Admin
Joined: 08 Jan 2003 23:22 Posts: 22811 Location: Silicon Valley
|
Вот подсчитал среднеквадратичное отклонение стандартных EGA цветов от получившихся - результат не всегда совпадает с моим выбором (см.выше), но если выбрать следующий доступный цвет, то совпадает (за исключением коричневого EGA[6], которого у меня и близко нету): P.S. Ещё можно попробовать посмешивать 2 цвета - может быть более похоже: Вот такая вот аппроксимация EGA-шных цветов получилась:
|
09 Apr 2015 20:14 |
|
|
Shaos
Admin
Joined: 08 Jan 2003 23:22 Posts: 22811 Location: Silicon Valley
|
|
09 Apr 2015 22:08 |
|
|
Shaos
Admin
Joined: 08 Jan 2003 23:22 Posts: 22811 Location: Silicon Valley
|
Интересная особенность выяснилась - оказывается, если ставить опцию оптимизации -O2, то оно ругается в лог сборки: Однако программа всё равно начинает работать чуть более чем в 2 раза быстрее! P.S. Может это 60-дневная PRO-evaluation включилась?... P.P.S. На самом деле оно просто от -O2 до -O1 даунгрейдилось, что опять же быстрее чем вообще без оптимизации - вот оно и срабатывало...
|
10 Apr 2015 14:13 |
|
|
Shaos
Admin
Joined: 08 Jan 2003 23:22 Posts: 22811 Location: Silicon Valley
|
Ещё старых дософских картинок вам
|
11 Apr 2015 02:49 |
|
|
Shaos
Admin
Joined: 08 Jan 2003 23:22 Posts: 22811 Location: Silicon Valley
|
На только что купленном (и относительно дешёвом) LED TV от LG цвета выглядят несколько иначе - первое, что бросается в глаза - это намного более тёмный серый (две полоски 0101 и 1010), а также более тёмные magent-ы, зато тёмно-красный выглядит как красный:
|
12 Apr 2015 16:38 |
|
|
Shaos
Admin
Joined: 08 Jan 2003 23:22 Posts: 22811 Location: Silicon Valley
|
В-принципе, цвета похожи на то, что должно быть (CGA/EGA) - вот так их показывали (согласно википедии) CGA-карочки на NTSC телевизорах (вместо коричневого на цвете номер 6 был тёмно-жёлтый): Сравнение цветов с двух ТВ (фотик немного увёл цвета, причём на втором ТВ сильнее, чем на первом) с тем, что должно быть (цвет 6 показан для обоих вариантов NTSC и RGBI):
|
12 Apr 2015 18:09 |
|
|
Shaos
Admin
Joined: 08 Jan 2003 23:22 Posts: 22811 Location: Silicon Valley
|
Ещё скриншотов с ТВ
|
13 Apr 2015 17:04 |
|
|
Who is online |
Users browsing this forum: No registered users and 1 guest |
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot post attachments in this forum
|
|