Плата центрального недопроцессора nedoCPU-32

8-битные микроконтроллеры PICmicro (ПИКи) от Microchip и совместимые, а также 16-битные PIC24 и 32-битные PIC32

Moderator: Shaos

User avatar
Shaos
Admin
Posts: 23989
Joined: 08 Jan 2003 23:22
Location: Silicon Valley

Re: Плата центрального недопроцессора nedoCPU-32

Post by Shaos »

Stan wrote:
Shaos wrote:Интересной особенностью параллельного мастер порта (сигналы PMxx) является то, что на него можно натравить DMA, которое может брать последовательность байтов из памяти и колбасить их в порт - это можно использовать для генерации видео...
На фотографиях это точечная графика через PIC32 или всё же псевдографический режим?
Если точечная графика, то какой размер растра?
По вышеприведённому линку всё написано: http://hackaday.io/project/2032-pic32-oscilloscope

Точечная графика 256x200

Или мы по ангельски не разумеем?...
Я тут за главного - если что шлите мыло на me собака shaos точка net
User avatar
Shaos
Admin
Posts: 23989
Joined: 08 Jan 2003 23:22
Location: Silicon Valley

Re: Плата центрального недопроцессора nedoCPU-32

Post by Shaos »

Подменил фонт на свой, который юзался в NedoText и тоже 5x7:
You do not have the required permissions to view the files attached to this post.
Я тут за главного - если что шлите мыло на me собака shaos точка net
User avatar
Shaos
Admin
Posts: 23989
Joined: 08 Jan 2003 23:22
Location: Silicon Valley

Re: Плата центрального недопроцессора nedoCPU-32

Post by Shaos »

А вот недофонт 8x8, использованный в Circuits.CC - теперь можно строить nedoPC-32 :idea:
You do not have the required permissions to view the files attached to this post.
Я тут за главного - если что шлите мыло на me собака shaos точка net
User avatar
Shaos
Admin
Posts: 23989
Joined: 08 Jan 2003 23:22
Location: Silicon Valley

Re: Плата центрального недопроцессора nedoCPU-32

Post by Shaos »

Вот ещё немного экспериментов с недофонтом (как видно на большом ТВ картинка вылазит за пределы экрана по горизонтали):
You do not have the required permissions to view the files attached to this post.
Я тут за главного - если что шлите мыло на me собака shaos точка net
User avatar
Shaos
Admin
Posts: 23989
Joined: 08 Jan 2003 23:22
Location: Silicon Valley

Re: Плата центрального недопроцессора nedoCPU-32

Post by Shaos »

Пересчитал частоту на 64 МГц и сдвинул кадр чуть вправо, оставив колбасню DMA без изменений - всё влезло:
You do not have the required permissions to view the files attached to this post.
Я тут за главного - если что шлите мыло на me собака shaos точка net
User avatar
Shaos
Admin
Posts: 23989
Joined: 08 Jan 2003 23:22
Location: Silicon Valley

Re: Плата центрального недопроцессора nedoCPU-32

Post by Shaos »

Вот исходник под 64 МГц, из которого выкинуто всё лишнее, а также оптимизировано:

 исходник тут

Code: Select all

/*********************************************************************
 *
 * Based on "NTSC TV interface" examples from 
 * 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
 *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 *
 * SCK1 is pin 25
 * SDO1 is PPS group 2, map to RPA1 (pin 3)
 * SDI1 is PPS group 2, map to RPB8 (pin 17)
 *
 * VIDEO is PortA.1 
 * SYNC  is PortB.5
 *
 */

#include <plib.h>
#include <xc.h> // need for pps
#include <stdio.h>

// Recalculated to 64 MHz to fit into NTSC screen
//                       8MHZ                          4MHz               64MHz            32   <-----<---    64MHz
#pragma config FNOSC = FRCPLL, POSCMOD = OFF, FPLLIDIV = DIV_2, FPLLMUL = MUL_16, FPBDIV = DIV_2, FPLLODIV = DIV_1
#pragma config FWDTEN = OFF
#pragma config FSOSCEN = OFF, JTAGEN = OFF
// core frequency we're running at // peripherals at 40 MHz
#define	SYS_FREQ 64000000

// The SPI channel
volatile SpiChannel spiChn = SPI_CHANNEL1 ;	// the SPI channel to use
volatile int spiClkDiv = 6 ;//5.333 MHz pixel rate => 256 points in 48 us

#define DX 256
#define DY 200

// main screen buffer array 256 wide x 200 high = 51200 pixels
// 51200/32 = 1600 integer words
int screen_buffer[1600] ;
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 2032 // 63.5 uSec at 32 MHz Fpb, prescaler=1
#define us_5_cycles  160 // 5 uSec at 30 MHz Fpb, prescaler=1
#define us_11_cycles 352 // beginning of the video DMA burst -- use for centering

// video active lines -- 200 total
#define image_start 20
#define image_end (image_start+DY)
#define top 0
#define left 0
#define right (DX-1)
#define bottom (DY-1)

// 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 ;

#include "nedofont.h"

// == OC3 ISR ============================================
// VECTOR 14 is OC3 vector -- set up of ipl 3 in main
// vector names from int_1xx_2xx.h
void __ISR(14, ipl3) OC3Handler(void) // 14
{
   // 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
}

// == 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++ ;

    // start the DMA byte blaster to the screen
    if (LineCount >= image_start && LineCount < image_end){
        // 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, 32, 4, 4); //32
        // 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 += 8; // 8 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
        time_tick_60_hz++;        
    }
    // == 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;
    }
    
    // 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) {
	//each line has 18 bytes
	//calculate i based upon this and x,y
	// the word with the pixel in it
	//int i = (x/32) + y*8
	if (c==1)
	  screen_buffer[(x >> 5) + (y << 3)] |= 1<<(31-(x & 0x1f));
    else if (c==0)
	  screen_buffer[(x >> 5) + (y << 3)] &= ~(1<<(31-(x & 0x1f)));
    else // c==2
	  screen_buffer[(x >> 5) + (y << 3)] ^= 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 >> 5) + (y << 3)] & (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) {
    int i,j = (x>>2)+(y<<6);
    int shf = (3-(x&3))<<3;
    for (i=0;i<7;i++) {
        screen_buffer[j]=(screen_buffer[j]&(~(255<<shf)))|(font8x8[c-32][i]<<shf);
        j += 8;
    }
}

//==================================
// 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	main(void)
{
    int frame,seconds;
    unsigned long n;
    // global time
    int time ;
    char cu1[]="nedoPC-32-A v1.0";
    char cu2[]="March 2015";
    char time_string[10] ;

	// 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
    // at 40 MHz PB clock 63.5 microSec is
    // 2540 ticks
    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 RPB5 (pin 14)
    PPSOutput(2, RPB5, 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 , us_11_cycles+2, us_11_cycles); //
    // 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

    // 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_1 | BIT_5);
    mPORTBSetBits(BIT_0);

    // divide Fpb by spiClkDiv, configure the I/O ports.
    // 32 bit transfer
    SpiChnOpen(spiChn, SPI_OPEN_ON | SPI_OPEN_MODE32 | SPI_OPEN_MSTEN , spiClkDiv ) ;

    //=== DMA Channel 1 ================================
    // Open DMA Chan1 and chain from channel zero
    DmaChnOpen(DMAchn1, DMApri0, DMA_OPEN_DEFAULT);

    // setup system wide interrupts  ///
    INTEnableSystemMultiVectoredInt();

    // 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

    // Draw a title
    video_string(1,1,cu1);
    video_string(21,1,cu2);
   
    frame = seconds = 0;
	while(1)
	{
            n = 0;
            // wait until the next 1/60 second
            while(time == time_tick_60_hz){n++;}
            // use ISR time-tick to update time stamp
            mPORTBSetBits(BIT_1); // for profiling execution time
            time = time_tick_60_hz ;
            if(++frame==60)
            {
                frame = 0;
                sprintf(time_string, "%d:%u ",++seconds,n);
                video_string(1, 23, time_string);
            }
            mPORTBClearBits(BIT_1); // for profiling execution time
 	}

}

P.S. В пределах одного кадра (60 раз в секунду) цикл while(time == time_tick_60_hz){n++;} выполняется 110936 раз - не густо...
You do not have the required permissions to view the files attached to this post.
Я тут за главного - если что шлите мыло на me собака shaos точка net
User avatar
Shaos
Admin
Posts: 23989
Joined: 08 Jan 2003 23:22
Location: Silicon Valley

Re: Плата центрального недопроцессора nedoCPU-32

Post by Shaos »

Вот ещё более оптимизированная программка (подсчёт секунд выведен в прерывание и развёрнут цикл печати символа) - в пределах кадра (1/60 секунды) успевает вывестись 2670 случайных символов в верхние 16 строк (а всего одновременно на экран влезают 32*25=800 символов):

 исходник тут

Code: Select all

/*********************************************************************
 *
 * Based on "NTSC TV interface" examples from 
 * 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
 *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 *
 * SCK1 is pin 25
 * SDO1 is PPS group 2, map to RPA1 (pin 3)
 * SDI1 is PPS group 2, map to RPB8 (pin 17)
 *
 * VIDEO is PortA.1 
 * SYNC  is PortB.5
 *
 */

#include <plib.h>
#include <xc.h> // need for pps
#include <stdio.h>
#include <stdlib.h>

// Recalculated to 64 MHz to fit into NTSC screen
//                       8MHZ                          4MHz               64MHz            32   <-----<---    64MHz
#pragma config FNOSC = FRCPLL, POSCMOD = OFF, FPLLIDIV = DIV_2, FPLLMUL = MUL_16, FPBDIV = DIV_2, FPLLODIV = DIV_1
#pragma config FWDTEN = OFF
#pragma config FSOSCEN = OFF, JTAGEN = OFF
// core frequency we're running at // peripherals at 40 MHz
#define	SYS_FREQ 64000000

// The SPI channel
volatile SpiChannel spiChn = SPI_CHANNEL1 ;	// the SPI channel to use
volatile int spiClkDiv = 6 ;//5.333 MHz pixel rate => 256 points in 48 us

#define DX 256
#define DY 200

// main screen buffer array 256 wide x 200 high = 51200 pixels
// 51200/32 = 1600 integer words
int screen_buffer[1600] ;
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 2032 // 63.5 uSec at 32 MHz Fpb, prescaler=1
#define us_5_cycles  160 // 5 uSec at 30 MHz Fpb, prescaler=1
#define us_11_cycles 352 // beginning of the video DMA burst -- use for centering

// video active lines -- 200 total
#define image_start 20
#define image_end (image_start+DY)
#define top 0
#define left 0
#define right (DX-1)
#define bottom (DY-1)

// 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;

#include "nedofont.h"

// == OC3 ISR ============================================
// VECTOR 14 is OC3 vector -- set up of ipl 3 in main
// vector names from int_1xx_2xx.h
void __ISR(14, ipl3) OC3Handler(void) // 14
{
   // 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
}

// == 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++ ;

    // start the DMA byte blaster to the screen
    if (LineCount >= image_start && LineCount < image_end){
        // 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, 32, 4, 4); //32
        // 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 += 8; // 8 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;
    }
    
    // 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) {
	//each line has 18 bytes
	//calculate i based upon this and x,y
	// the word with the pixel in it
	//int i = (x/32) + y*8
	if (c==1)
	  screen_buffer[(x >> 5) + (y << 3)] |= 1<<(31-(x & 0x1f));
    else if (c==0)
	  screen_buffer[(x >> 5) + (y << 3)] &= ~(1<<(31-(x & 0x1f)));
    else // c==2
	  screen_buffer[(x >> 5) + (y << 3)] ^= 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 >> 5) + (y << 3)] & (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) {
    int j = (x>>2)+(y<<6);
    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+=8;
    screen_buffer[j]=(screen_buffer[j] & msk)|(*(ptr++)<<shf);j+=8;
    screen_buffer[j]=(screen_buffer[j] & msk)|(*(ptr++)<<shf);j+=8;
    screen_buffer[j]=(screen_buffer[j] & msk)|(*(ptr++)<<shf);j+=8;
    screen_buffer[j]=(screen_buffer[j] & msk)|(*(ptr++)<<shf);j+=8;
    screen_buffer[j]=(screen_buffer[j] & msk)|(*(ptr++)<<shf);j+=8;
    screen_buffer[j]=(screen_buffer[j] & msk)|(*(ptr++)<<shf);j+=8;
    screen_buffer[j]=(screen_buffer[j] & msk)|(*ptr<<shf);
}

//==================================
// 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	main(void)
{
    unsigned long n, stored;
    // global time
    int time, seconds, k, c;
    char cu1[]="nedoPC-32-A v1.0";
    char cu2[]="March 2015";
    char time_string[10] ;

	// 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
    // at 40 MHz PB clock 63.5 microSec is
    // 2540 ticks
    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 RPB5 (pin 14)
    PPSOutput(2, RPB5, 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 , us_11_cycles+2, us_11_cycles); //
    // 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

    // 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_1 | BIT_5);
    mPORTBSetBits(BIT_0);

    // divide Fpb by spiClkDiv, configure the I/O ports.
    // 32 bit transfer
    SpiChnOpen(spiChn, SPI_OPEN_ON | SPI_OPEN_MODE32 | SPI_OPEN_MSTEN , spiClkDiv ) ;

    //=== DMA Channel 1 ================================
    // Open DMA Chan1 and chain from channel zero
    DmaChnOpen(DMAchn1, DMApri0, DMA_OPEN_DEFAULT);

    // setup system wide interrupts  ///
    INTEnableSystemMultiVectoredInt();

    // 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

    // Draw a title
    video_string(1,1,cu1);
    video_string(21,1,cu2);

    seconds = stored = n = 0;
    c = 32;
    srand(11111);
	while(1)
	{       
            n++;
            k = rand();
            video_putchar(k&31,(k>>5)&15,++c);
            if(c==255) c=31;
            // wait until the next 1/60 second
            if(time != time_tick_60_hz)
            {
                time = time_tick_60_hz ;
                stored = n;
                n = 0;                
            }
            if(seconds != time_seconds)
            {
                seconds = time_seconds;
                sprintf(time_string, "%d:%u ",seconds,stored);
                video_string(1, 23, time_string);
            }
 	}

}

You do not have the required permissions to view the files attached to this post.
Я тут за главного - если что шлите мыло на me собака shaos точка net
User avatar
Stan
Banned
Posts: 397
Joined: 04 Jan 2013 10:09
Location: 95.24.178.158

Re: Плата центрального недопроцессора nedoCPU-32

Post by Stan »

Shaos wrote:
Stan wrote:Если точечная графика, то какой размер растра?
По вышеприведённому линку всё написано: http://hackaday.io/project/2032-pic32-oscilloscope

Точечная графика 256x200

Или мы по ангельски не разумеем?...
Трудно мне сказать, разумеете вы "по ангельски" или нет, но короткого ответа по-русски: "Точечная графика 256x200" мне вполне достаточно. :idea:
На прочие "мовы", можете не трудиться переводить. :dj:
User avatar
Shaos
Admin
Posts: 23989
Joined: 08 Jan 2003 23:22
Location: Silicon Valley

Re: Плата центрального недопроцессора nedoCPU-32

Post by Shaos »

А вот рисование случайных линий - порядка 100 линий за кадр получается (а если закомментить линии и раскомментить пикселы, то будет около 7000 случайных пикселов за кадр):

 исходник тут

Code: Select all

/*********************************************************************
 *
 * Based on "NTSC TV interface" examples from 
 * 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
 *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 *
 * SCK1 is pin 25
 * SDO1 is PPS group 2, map to RPA1 (pin 3)
 * SDI1 is PPS group 2, map to RPB8 (pin 17)
 *
 * VIDEO is PortA.1 
 * SYNC  is PortB.5
 *
 */

#include <plib.h>
#include <xc.h> // need for pps
#include <stdio.h>
#include <stdlib.h>

// Recalculated to 64 MHz to fit into NTSC screen
//                       8MHZ                          4MHz               64MHz            32   <-----<---    64MHz
#pragma config FNOSC = FRCPLL, POSCMOD = OFF, FPLLIDIV = DIV_2, FPLLMUL = MUL_16, FPBDIV = DIV_2, FPLLODIV = DIV_1
#pragma config FWDTEN = OFF
#pragma config FSOSCEN = OFF, JTAGEN = OFF
// core frequency we're running at // peripherals at 40 MHz
#define	SYS_FREQ 64000000

// The SPI channel
volatile SpiChannel spiChn = SPI_CHANNEL1 ;	// the SPI channel to use
volatile int spiClkDiv = 6 ;//5.333 MHz pixel rate => 256 points in 48 us

#define DX 256
#define DY 200

// main screen buffer array 256 wide x 200 high = 51200 pixels
// 51200/32 = 1600 integer words
int screen_buffer[1600] ;
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 2032 // 63.5 uSec at 32 MHz Fpb, prescaler=1
#define us_5_cycles  160 // 5 uSec at 30 MHz Fpb, prescaler=1
#define us_11_cycles 352 // beginning of the video DMA burst -- use for centering

// video active lines -- 200 total
#define image_start 20
#define image_end (image_start+DY)
#define top 0
#define left 0
#define right (DX-1)
#define bottom (DY-1)

// 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;

#include "nedofont.h"

// == OC3 ISR ============================================
// VECTOR 14 is OC3 vector -- set up of ipl 3 in main
// vector names from int_1xx_2xx.h
void __ISR(14, ipl3) OC3Handler(void) // 14
{
   // 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
}

// == 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++ ;

    // start the DMA byte blaster to the screen
    if (LineCount >= image_start && LineCount < image_end){
        // 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, 32, 4, 4); //32
        // 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 += 8; // 8 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;
    }
    
    // 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) {
	//each line has 18 bytes
	//calculate i based upon this and x,y
	// the word with the pixel in it
	//int i = (x/32) + y*8
	if (c==1)
	  screen_buffer[(x >> 5) + (y << 3)] |= 1<<(31-(x & 0x1f));
    else if (c==0)
	  screen_buffer[(x >> 5) + (y << 3)] &= ~(1<<(31-(x & 0x1f)));
    else // c==2
	  screen_buffer[(x >> 5) + (y << 3)] ^= 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 >> 5) + (y << 3)] & (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) {
    int j = (x>>2)+(y<<6);
    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+=8;
    screen_buffer[j]=(screen_buffer[j] & msk)|(*(ptr++)<<shf);j+=8;
    screen_buffer[j]=(screen_buffer[j] & msk)|(*(ptr++)<<shf);j+=8;
    screen_buffer[j]=(screen_buffer[j] & msk)|(*(ptr++)<<shf);j+=8;
    screen_buffer[j]=(screen_buffer[j] & msk)|(*(ptr++)<<shf);j+=8;
    screen_buffer[j]=(screen_buffer[j] & msk)|(*(ptr++)<<shf);j+=8;
    screen_buffer[j]=(screen_buffer[j] & msk)|(*(ptr++)<<shf);j+=8;
    screen_buffer[j]=(screen_buffer[j] & msk)|(*ptr<<shf);
}

//==================================
// 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	main(void)
{
    unsigned long n, stored;
    // global time
    int time, seconds, x, y, k, c;
    char cu1[]="nedoPC-32-A v1.0";
    char cu2[]="March 2015";
    char time_string[10] ;

	// 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
    // at 40 MHz PB clock 63.5 microSec is
    // 2540 ticks
    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 RPB5 (pin 14)
    PPSOutput(2, RPB5, 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 , us_11_cycles+2, us_11_cycles); //
    // 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

    // 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_1 | BIT_5);
    mPORTBSetBits(BIT_0);

    // divide Fpb by spiClkDiv, configure the I/O ports.
    // 32 bit transfer
    SpiChnOpen(spiChn, SPI_OPEN_ON | SPI_OPEN_MODE32 | SPI_OPEN_MSTEN , spiClkDiv ) ;

    //=== DMA Channel 1 ================================
    // Open DMA Chan1 and chain from channel zero
    DmaChnOpen(DMAchn1, DMApri0, DMA_OPEN_DEFAULT);

    // setup system wide interrupts  ///
    INTEnableSystemMultiVectoredInt();

    // 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

    // Draw a title
    video_string(1,1,cu1);
    video_string(21,1,cu2);

    seconds = stored = n = x = y = 0;
    c = 32;
    srand(11111);
	while(1)
	{       
            n++;
            k = rand();
#if 0
            // random characters
            video_putchar(k&31,2+((k>>5)&15),++c);
            if(c==255) c=31;
#else
            // random lines
            c = k&255; k=16+((k>>8)%168);
            video_line(x,y,c,k,2);
            x = c; y = k;
            // random pixels
//            video_pt(k&255,16+((k>>8)%168),2);
#endif
            if(time != time_tick_60_hz)
            {
                time = time_tick_60_hz ;
                stored = n;
                n = 0;                
            }
            if(seconds != time_seconds)
            {
                seconds = time_seconds;
                sprintf(time_string, "%d:%u ",seconds,stored);
                video_string(1, 23, time_string);
            }
 	}

}

You do not have the required permissions to view the files attached to this post.
Я тут за главного - если что шлите мыло на me собака shaos точка net
User avatar
Shaos
Admin
Posts: 23989
Joined: 08 Jan 2003 23:22
Location: Silicon Valley

Re: Плата центрального недопроцессора nedoCPU-32

Post by Shaos »

Ну и наконец показывание вкомпилированных в код XBM-картинок :)

P.S. Это моя старшая дочка в Magic Kingdom (Disney World)

P.P.S. 19575 - это количество вызовов rand(), умещающихся в один кадр (1/60 секунды)

 исходник тут

Code: Select all

/*********************************************************************
 *
 * Based on "NTSC TV interface" examples from 
 * 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
 *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 *
 * SCK1 is pin 25
 * SDO1 is PPS group 2, map to RPA1 (pin 3)
 * SDI1 is PPS group 2, map to RPB8 (pin 17)
 *
 * VIDEO is PortA.1 
 * SYNC  is PortB.5
 *
 */

#include <plib.h>
#include <xc.h> // need for pps
#include <stdio.h>
#include <stdlib.h>

// Recalculated to 64 MHz to fit into NTSC screen
//                       8MHZ                          4MHz               64MHz            32   <-----<---    64MHz
#pragma config FNOSC = FRCPLL, POSCMOD = OFF, FPLLIDIV = DIV_2, FPLLMUL = MUL_16, FPBDIV = DIV_2, FPLLODIV = DIV_1
#pragma config FWDTEN = OFF
#pragma config FSOSCEN = OFF, JTAGEN = OFF
// core frequency we're running at // peripherals at 40 MHz
#define	SYS_FREQ 64000000

// The SPI channel
volatile SpiChannel spiChn = SPI_CHANNEL1 ;	// the SPI channel to use
volatile int spiClkDiv = 6 ;//5.333 MHz pixel rate => 256 points in 48 us

#define DX 256
#define DY 200

// main screen buffer array 256 wide x 200 high = 51200 pixels
// 51200/32 = 1600 integer words
#define SCREENSZ 1600
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 2032 // 63.5 uSec at 32 MHz Fpb, prescaler=1
#define us_5_cycles  160 // 5 uSec at 30 MHz Fpb, prescaler=1
#define us_11_cycles 352 // beginning of the video DMA burst -- use for centering

// video active lines -- 200 total
#define image_start 20
#define image_end (image_start+DY)
#define top 0
#define left 0
#define right (DX-1)
#define bottom (DY-1)

// 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;

#include "nedofont.h"

#include "katya_bw.xbm"
#include "dolphin.xbm"

// == OC3 ISR ============================================
// VECTOR 14 is OC3 vector -- set up of ipl 3 in main
// vector names from int_1xx_2xx.h
void __ISR(14, ipl3) OC3Handler(void) // 14
{
   // 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
}

// == 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++ ;

    // start the DMA byte blaster to the screen
    if (LineCount >= image_start && LineCount < image_end){
        // 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, 32, 4, 4); //32
        // 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 += 8; // 8 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;
    }
    
    // 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) {
	//each line has 18 bytes
	//calculate i based upon this and x,y
	// the word with the pixel in it
	//int i = (x/32) + y*8
	if (c==1)
	  screen_buffer[(x >> 5) + (y << 3)] |= 1<<(31-(x & 0x1f));
    else if (c==0)
	  screen_buffer[(x >> 5) + (y << 3)] &= ~(1<<(31-(x & 0x1f)));
    else // c==2
	  screen_buffer[(x >> 5) + (y << 3)] ^= 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 >> 5) + (y << 3)] & (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) {
    int j = (x>>2)+(y<<6);
    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+=8;
    screen_buffer[j]=(screen_buffer[j] & msk)|(*(ptr++)<<shf);j+=8;
    screen_buffer[j]=(screen_buffer[j] & msk)|(*(ptr++)<<shf);j+=8;
    screen_buffer[j]=(screen_buffer[j] & msk)|(*(ptr++)<<shf);j+=8;
    screen_buffer[j]=(screen_buffer[j] & msk)|(*(ptr++)<<shf);j+=8;
    screen_buffer[j]=(screen_buffer[j] & msk)|(*(ptr++)<<shf);j+=8;
    screen_buffer[j]=(screen_buffer[j] & msk)|(*(ptr++)<<shf);j+=8;
    screen_buffer[j]=(screen_buffer[j] & msk)|(*ptr<<shf);
}

//==================================
// 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	main(void)
{
    int* iptr;
    unsigned long i,j,n,m,stored;
    // global time
    int time, seconds, x, y, k, c;
    char time_string[10] ;

	// 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
    // at 40 MHz PB clock 63.5 microSec is
    // 2540 ticks
    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 RPB5 (pin 14)
    PPSOutput(2, RPB5, 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 , us_11_cycles+2, us_11_cycles); //
    // 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

    // 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_1 | BIT_5);
    mPORTBSetBits(BIT_0);

    // divide Fpb by spiClkDiv, configure the I/O ports.
    // 32 bit transfer
    SpiChnOpen(spiChn, SPI_OPEN_ON | SPI_OPEN_MODE32 | SPI_OPEN_MSTEN , spiClkDiv ) ;

    //=== DMA Channel 1 ================================
    // Open DMA Chan1 and chain from channel zero
    DmaChnOpen(DMAchn1, DMApri0, DMA_OPEN_DEFAULT);

    // setup system wide interrupts  ///
    INTEnableSystemMultiVectoredInt();

    iptr = (int*)katya_bw_bits;
//    iptr = (int*)dolphin_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;
    }
    
    // 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

    // Draw a title
    video_string(1,1,"nedoPC-32-A v1.0 (March 2015) ");

    seconds = stored = n = x = y = 0;
    c = 32;
    srand(11111);
	while(1)
	{       
            n++;
            k = rand();
#if 0
            // random characters
            video_putchar(k&31,2+((k>>5)&15),++c);
            if(c==255) c=31;
#endif
#if 0
            // random lines
            c = k&255; k=16+((k>>8)%168);
            video_line(x,y,c,k,2);
            x = c; y = k;
#endif
#if 0
            // random pixels
            video_pt(k&255,16+((k>>8)%168),2);
#endif
            if(time != time_tick_60_hz)
            {
                time = time_tick_60_hz ;
                stored = n;
                n = 0;                
            }
            if(seconds != time_seconds)
            {
                seconds = time_seconds;
                sprintf(time_string, "%d:%u ",seconds,stored);
                video_string(1, 23, time_string);
            }
 	}

}

You do not have the required permissions to view the files attached to this post.
Я тут за главного - если что шлите мыло на me собака shaos точка net
User avatar
Shaos
Admin
Posts: 23989
Joined: 08 Jan 2003 23:22
Location: Silicon Valley

Re: Плата центрального недопроцессора nedoCPU-32

Post by Shaos »

Ещё фоточка, выведенная через PIC32 (если в исходнике раскомментить dolphin_bits):
You do not have the required permissions to view the files attached to this post.
Я тут за главного - если что шлите мыло на me собака shaos точка net
User avatar
Shaos
Admin
Posts: 23989
Joined: 08 Jan 2003 23:22
Location: Silicon Valley

Re: Плата центрального недопроцессора nedoCPU-32

Post by Shaos »

Если верить автору, то такой способ работы с графикой отнимает только 8% процессорного времени, а это значит, что при наличии языка Си, 64МГц 32-битного проца, 256Кб флеша и 64Кб ОЗУ, можно много прикольных штук понаделать, не смотря на ограничения графики - ну что, делаем чёрно-белую игровую приставку? :idea:

P.S. Кстати я тут прикинул, что несложно будет цвет снаружи добавить как опциональную первую палитру CGA с её олдскульными 4 цветами (black, cyan, magenta, white), правда разрешение тогда станет не 256x200, а 128x200...

P.P.S. Хотя судя по всему код в лёгкую перенастраивается на более длинные строки, однако при этом проц будет жраться интенсивнее...

P.P.P.S. Ради эксперимента перенастроил на 640 пикселов в строке (и соответственно на более частую работу DMA) - ухудшений в производительности главного цикла не заметил...
Я тут за главного - если что шлите мыло на me собака shaos точка net
User avatar
Shaos
Admin
Posts: 23989
Joined: 08 Jan 2003 23:22
Location: Silicon Valley

Re: Плата центрального недопроцессора nedoCPU-32

Post by Shaos »

Можно примерно подсчитать стоимость минимального игрового компьютера на PIC32, если бы пользователь собирал его сам на бредборде (по ценам DigiKey):

IC1: PIC32MX170F256B-I/SP - $4.49
LED1: красный светодиод 5 мм - $0.15
C1,C2: ненужны, если питаемся от батареек
C3,C4,C6: 0.1uF (ceramic) - 3*$0.24 = $0.72
C5: 10uF (ceramic) - $0.49
C7: ненужен, если питаемся от батареек
C8,C9: ненужны
R1: 10 Ohm - $0.10
R2: 10 kOhm - $0.10
R3,R4: 470 Ohm - 2*$0.10 = $0.20
X5: хедер для PICkit3 - примерно $0.20
S1-S7: кнопка ресета и игровые кнопки - 7*$0.12 = $0.72
Резисторы для кнопок - 6*$0.10 = $0.60
RCA разъёмы (звук и видео) - 2*$1 = $2 (примерно)
Резисторы для звука и видео - 5*$0.10 = $0.50
Держатель для двух пальчиковых батареек - $1 (плюс-минус)
Две пальчиковые батарейки - 2*$1 = $2 (примерно)

Всего $13.27 плюс бредборда и проводочки (ну скажем ещё $5) - по моему очень неплохо...
Я тут за главного - если что шлите мыло на me собака shaos точка net
User avatar
Shaos
Admin
Posts: 23989
Joined: 08 Jan 2003 23:22
Location: Silicon Valley

Re: Плата центрального недопроцессора nedoCPU-32

Post by Shaos »

Shaos wrote:P.S. Кстати я тут прикинул, что несложно будет цвет снаружи добавить как опциональную первую палитру CGA с её олдскульными 4 цветами (black, cyan, magenta, white), правда разрешение тогда станет не 256x200, а 128x200...
Суть в том, что пикселы выдаются наружу через SPI, у которого есть клок на отдельной ноге (проверил осциллографом, что действительно есть, причём только когда выводятся пикселы изображения), т.е. мы можем сохранять чётный пиксел, чтобы потом с нечётным сформировать 2-битный цвет с 2 раза меньшим горизонтальным разрешением, например на палке-галке...

P.S. Переставил синхру с PortB.5 на PortB.1, освободив тем самым 8 контактов подряд для кнопок - от PortB.4 до PortB.11

P.P.S. А на PortB.2 и PortB.3 можно выдавать 2-битный звук с частотой дискретизации 15734.2 Гц (частота строчной развёртки NTSC)...

 исходник тут

Code: Select all

/*********************************************************************
 *
 * Based on "NTSC TV interface" examples from
 * 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>

// Recalculated to 64 MHz to fit into NTSC screen
//                       8MHZ                          4MHz               64MHz            32   <-----<---    64MHz
#pragma config FNOSC = FRCPLL, POSCMOD = OFF, FPLLIDIV = DIV_2, FPLLMUL = MUL_16, FPBDIV = DIV_2, FPLLODIV = DIV_1
#pragma config FWDTEN = OFF
#pragma config FSOSCEN = OFF, JTAGEN = OFF
// core frequency we're running at // peripherals at 40 MHz
#define   SYS_FREQ 64000000

#define DX 256
#define DY 200

// main screen buffer array 256 wide x 200 high = 51200 pixels
// 51200/32 = 1600 integer words
#define SCREENSZ 1600
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 2032 // 63.5 uSec at 32 MHz Fpb, prescaler=1
#define us_5_cycles  160 // 5 uSec at 32 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 (DX-1)
#define bottom (DY-1)

// 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;

#include "nedofont.h"

#include "katya_bw.xbm"
#include "dolphin.xbm"

// == OC3 ISR ============================================
// VECTOR 14 is OC3 vector -- set up of ipl 3 in main
// vector names from int_1xx_2xx.h
void __ISR(14, ipl3) OC3Handler(void) // 14
{
   // 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
}

// == 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++ ;

    // start the DMA byte blaster to the screen
    if (LineCount >= image_start && LineCount < image_end){
        // 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, 32, 4, 4); //32
        // 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 += 8; // 8 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;
    }
   
    // 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) {
   //each line has 18 bytes
   //calculate i based upon this and x,y
   // the word with the pixel in it
   //int i = (x/32) + y*8
   if (c==1)
     screen_buffer[(x >> 5) + (y << 3)] |= 1<<(31-(x & 0x1f));
    else if (c==0)
     screen_buffer[(x >> 5) + (y << 3)] &= ~(1<<(31-(x & 0x1f)));
    else // c==2
     screen_buffer[(x >> 5) + (y << 3)] ^= 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 >> 5) + (y << 3)] & (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) {
    int j = (x>>2)+(y<<6);
    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+=8;
    screen_buffer[j]=(screen_buffer[j] & msk)|(*(ptr++)<<shf);j+=8;
    screen_buffer[j]=(screen_buffer[j] & msk)|(*(ptr++)<<shf);j+=8;
    screen_buffer[j]=(screen_buffer[j] & msk)|(*(ptr++)<<shf);j+=8;
    screen_buffer[j]=(screen_buffer[j] & msk)|(*(ptr++)<<shf);j+=8;
    screen_buffer[j]=(screen_buffer[j] & msk)|(*(ptr++)<<shf);j+=8;
    screen_buffer[j]=(screen_buffer[j] & msk)|(*(ptr++)<<shf);j+=8;
    screen_buffer[j]=(screen_buffer[j] & msk)|(*ptr<<shf);
}

//==================================
// 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   main(void)
{
    int* iptr;
    unsigned long i,j,n,m,stored;
    // global time
    int time, seconds, x, y, k, c;
    char time_string[10] ;

   // 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
    // at 40 MHz PB clock 63.5 microSec is
    // 2540 ticks
    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, 354, 352); // 354,352
    // 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

    // 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 , 6); // N=6

    //=== DMA Channel 1 ================================
    // Open DMA Chan1 and chain from channel zero
    DmaChnOpen(DMAchn1, DMApri0, DMA_OPEN_DEFAULT);

    // setup system wide interrupts  ///
    INTEnableSystemMultiVectoredInt();

    iptr = (int*)katya_bw_bits;
//    iptr = (int*)dolphin_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;
    }
   
    // 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

    // Draw a title
    video_string(1,1,"nedoPC-32-A v1.0 (March 2015) ");

    seconds = stored = n = x = y = 0;
    c = 32;
    srand(11111);
    while(1)
    {       
            n++;
#if 0
            // random characters
            k = rand();
            video_putchar(k&31,2+((k>>5)&15),++c);
            if(c==255) c=31;
#endif
#if 0
            // random lines
            k = rand();
            c = k&255; k=16+((k>>8)%168);
            video_line(x,y,c,k,2);
            x = c; y = k;
#endif
#if 0
            // random pixels
            k = rand();
            video_pt(k&255,16+((k>>8)%168),2);
#endif
            if(time != time_tick_60_hz)
            {
                time = time_tick_60_hz ;
                stored = n;
                n = 0;               
            }
            if(seconds != time_seconds)
            {
                seconds = time_seconds;
                sprintf(time_string, "%d:%4.4X ",seconds,PORTB);//stored);
                video_string(1, 23, time_string);
                
                if(seconds&1)
                    mPORTBClearBits(BIT_2);
                else
                    mPORTBSetBits(BIT_2);

                if(seconds&2)
                    mPORTBClearBits(BIT_3);
                else
                    mPORTBSetBits(BIT_3);
            }
    }

}

Я тут за главного - если что шлите мыло на me собака shaos точка net
User avatar
Shaos
Admin
Posts: 23989
Joined: 08 Jan 2003 23:22
Location: Silicon Valley

Re: Плата центрального недопроцессора nedoCPU-32

Post by Shaos »

С другой стороны зачем 2-битный звук, если можно сделать ШИМ на блоке Compare, которых ещё осталось?...

P.S. Подцепил 2 Compare - один будет ШИМ на звук, а второй - на подсветку отдельных строк ;)

 исходник тут

Code: Select all

/*********************************************************************
 *
 * Based on "NTSC TV interface" examples from
 * 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>

// Recalculated to 64 MHz to fit into NTSC screen
//                       8MHZ                          4MHz               64MHz            32   <-----<---    64MHz
#pragma config FNOSC = FRCPLL, POSCMOD = OFF, FPLLIDIV = DIV_2, FPLLMUL = MUL_16, FPBDIV = DIV_2, FPLLODIV = DIV_1
#pragma config FWDTEN = OFF
#pragma config FSOSCEN = OFF, JTAGEN = OFF
// core frequency we're running at // peripherals at 40 MHz
#define   SYS_FREQ 64000000

#define DX 256
#define DY 200

// main screen buffer array 256 wide x 200 high = 51200 pixels
// 51200/32 = 1600 integer words
#define SCREENSZ 1600
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 2032 // 63.5 uSec at 32 MHz Fpb, prescaler=1
#define line_offset  352 // offset to start video screen
#define us_5_cycles  160 // 5 uSec at 32 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 (DX-1)
#define bottom (DY-1)

// 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;

#include "nedofont.h"

#include "katya_bw.xbm"
#include "dolphin.xbm"

// == 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
{
   // 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,880,1006,1124,1232,1324,1399,1454,1488,1499,1488,1454,1399,1324,1232,1125,
1006,880,750,619,493,375,267,175,100,45,11,0,11,45,100,175,
267,374,493,619,749,880,1006,1124,1232,1324,1399,1454,1488,1499,1488,1454,
1399,1324,1232,1125,1006,880,750,619,493,375,267,175,100,45,11,0,
11,45,100,175,267,374,493,619,749,880,1006,1124,1232,1324,1399,1454,
1488,1499,1488,1454,1399,1324,1232,1125,1006,880,750,619,493,375,267,175,
100,45,11,0,11,45,100,175,267,374,493,619,749,880,1006,1124,
1232,1324,1399,1454,1488,1499,1488,1454,1399,1324,1232,1125,1006,880,750,619,
493,375,267,175,100,45,11,0,11,45,100,175,267,374,493,619,
749,880,1006,1124,1232,1324,1399,1454,1488,1499,1488,1454,1399,1324,1232,1125,
1006,880,750,619,493,375,267,175,100,45,11,0,11,45,100,175,
267,374,493,619,749,880,1006,1124,1232,1324,1399,1454,1488,1499,1488,1454,
1399,1324,1232,1125,1006,880,750,619,493,375,267,175,100,45,11,0,
11,45,100,175,267,374,493,619,749,880,1006,1124,1232,1324,1399,1454,
1488,1499,1488,1454,1399,1324,1232,1125,1006,880,750,619,493,375,267,175,
100,45,11,0,11,45,100,175,267,374,493,619,749,880,1006,1124,
1232,1324,1399,1454,1488,1499,1488,1454
};


// == 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);
    
    // start the DMA byte blaster to the screen
    if (LineCount >= image_start && LineCount < image_end){
        // 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, 32, 4, 4); //32
        // 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 += 8; // 8 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;
    }
   
    // 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) {
   //each line has 18 bytes
   //calculate i based upon this and x,y
   // the word with the pixel in it
   //int i = (x/32) + y*8
   if (c==1)
     screen_buffer[(x >> 5) + (y << 3)] |= 1<<(31-(x & 0x1f));
    else if (c==0)
     screen_buffer[(x >> 5) + (y << 3)] &= ~(1<<(31-(x & 0x1f)));
    else // c==2
     screen_buffer[(x >> 5) + (y << 3)] ^= 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 >> 5) + (y << 3)] & (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) {
    int j = (x>>2)+(y<<6);
    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+=8;
    screen_buffer[j]=(screen_buffer[j] & msk)|(*(ptr++)<<shf);j+=8;
    screen_buffer[j]=(screen_buffer[j] & msk)|(*(ptr++)<<shf);j+=8;
    screen_buffer[j]=(screen_buffer[j] & msk)|(*(ptr++)<<shf);j+=8;
    screen_buffer[j]=(screen_buffer[j] & msk)|(*(ptr++)<<shf);j+=8;
    screen_buffer[j]=(screen_buffer[j] & msk)|(*(ptr++)<<shf);j+=8;
    screen_buffer[j]=(screen_buffer[j] & msk)|(*(ptr++)<<shf);j+=8;
    screen_buffer[j]=(screen_buffer[j] & msk)|(*ptr<<shf);
}

//==================================
// 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   main(void)
{
    int* iptr;
    unsigned long i,j,n,m,stored;
    // global time
    int time, seconds, x, y, k, c;
    char time_string[10] ;

   // 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+2, line_offset);
    // OC4 is PPS group 3, map to RPA4 (pin 12)
    PPSOutput(3, RPA4, OC4);

    // OC5 setup /////////////////////////////////
//    OpenOC5(OC_ON | OC_TIMER2_SRC | OC_CONTINUE_PULSE, line_offset+2, line_offset);
    // 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 , 6); // N=6

    //=== DMA Channel 1 ================================
    // Open DMA Chan1 and chain from channel zero
    DmaChnOpen(DMAchn1, DMApri0, DMA_OPEN_DEFAULT);

    // setup system wide interrupts  ///
    INTEnableSystemMultiVectoredInt();

    iptr = (int*)katya_bw_bits;
//    iptr = (int*)dolphin_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;
    }
   
    // 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

    // Draw a title
    video_string(1,1,"nedoPC-32-A v1.0 (March 2015) ");

    seconds = stored = n = x = y = 0;
    c = 32;
    srand(11111);
    while(1)
    {       
            n++;
#if 0
            // random characters
            k = rand();
            video_putchar(k&31,2+((k>>5)&15),++c);
            if(c==255) c=31;
#endif
#if 0
            // random lines
            k = rand();
            c = k&255; k=16+((k>>8)%168);
            video_line(x,y,c,k,2);
            x = c; y = k;
#endif
#if 0
            // random pixels
            k = rand();
            video_pt(k&255,16+((k>>8)%168),2);
#endif
            if(time != time_tick_60_hz)
            {
                time = time_tick_60_hz ;
                stored = n;
                n = 0;               
            }
            if(seconds != time_seconds)
            {
                seconds = time_seconds;
                sprintf(time_string, "%d:%4.4X ",seconds,PORTB);//stored);
                video_string(1, 23, time_string);
                
                if(seconds&1)
                    mPORTBClearBits(BIT_2);
                else
                    mPORTBSetBits(BIT_2);

                if(seconds&2)
                    mPORTBClearBits(BIT_3);
                else
                    mPORTBSetBits(BIT_3);
            }
    }

}

You do not have the required permissions to view the files attached to this post.
Я тут за главного - если что шлите мыло на me собака shaos точка net