FDS184 / FDS185 met CPLD aansturen

Hallo allemaal,

Voor ik begin eerst dank aan iedereen die mee heeft geholpen bij het uitzoeken van de werking en aansturing van de FDS184/FDS185 borden en dan met name dank aan 'blurp' voor het uitzoeken van het CPLD 'protocol'

Er zijn hier al een aantal topics voorbij gekomen over het aansturen van de bekende FDS184 / FDS185 led matrix borden. Over het algemeen lijkt men er voor te kiezen om de CPLD er af te halen en de microcontroller rechtstreeks aan het schuifregister e.d te hangen.
Zelf heb ik dat pad in eerste instantie ook bewandeld en ben aan de slag gegaan met 3 schermen i.c.m een mbed controller. Al met al is dat prima gelukt maar een mbed controller is toch wel wat overkill en het vergt behoorlijk wat IO lijnen als je het allemaal aan 1 controller wilt hangen. Één controller per led matrix scherm is natuurlijk ook een optie maar dat is in de synchronisatie weer wat lastiger. Al met al voldoet de oplossing met de mbed controller prima voor die ene toepassing maar aangezien ik nog een paar led matrix borden had liggen vond ik de oplossing van blurp door de CPLD met slechts één IO lijn aan te sturen veel mooier.

Aangezien de puzzelstukjes die nodig zijn voor het aansturen van de CPLD redelijk verspreid zijn over dat topic ben ik er ingedoken om te kijken of ik die aansturing met behulp van een PIC16F1847 voor elkaar kon krijgen en eea goed vastleggen zodat het wellicht bruikbaar kan zijn voor anderen.

Waarom een PIC vraag je je misschien af.. Simpel antwoord, die had ik nog liggen. :)
Sterker nog, ik heb een hele voorraad verschillende PIC's liggen maar die bleken bijna allemaal van het 16LFxxx type te zijn waarbij het voltage tot max 3.Xxv gaat
en wel 5V tolerant op de IO zijn maar waarbij ik niet het risico wilde lopen dat de FDS184 die 3.xx op de RX niet opvangt.
Anyway, lang verhaal kort, de 16F1847 voldeed in de basis aan de voorwaarden en die waren in eerste instantie:

- Frequentie op 16Mhz
- Double buffer output (via EUSART synchronous mode, waarbij de clock niet gebruikt wordt)
De dubbele buffer is nodig om en 16 bits commando in 1 geheel uit te kunnen sturen.
- Datasnelheid op Fosc/4 (4Mhz)

Nadat de keuze van de PIC gemaakt was ben ik begonnen met het verwijderen van de 100ohm weerstand bij de TORX van het eerste bord
om in eerste instantie te gaan kijken of ik überhaupt iets op een scherm kon krijgen.
Dat bleek nog niet eenvoudig en er kwam wel wat op het scherm maar niet wat ik verwacht had.
Na veel testen, meten en proberen kwam ik achter de volgende (behoorlijk belangrijke!) zaken:

- MSB eerst
- Data lijn laag in idle mode

Het eerste probleem lag aan het feit dat de EUSART op de PIC16F1847 (en waarschijnlijk op vele andere PICs) de LSB eerst doet.
Je moet hier dus zelf voor corrigeren in de software d.m.v een bit reverse per byte die verstuurd wordt.
Het tweede probleem lag aan het feit dat de datalijn hoog blijft in idle mode wat waarschijnlijk (ik het dit nog niet doorgemeten)
door een pull-up op het ledmatrix bord komt. Volgens de datasheet zou de PIC de laatste bitwaarde volgen maar ook dit heb ik nog
niet geverifieerd.
De makkelijkste weg hier was om een 74HC04 hex inverter te pakken om het signaal te inverteren. Daarbij moeten ook alle commando's
in software geïnverteerd worden.

Na het nemen van al deze obstakels zag ik eindelijk het beroemde nijntje plaatje en was de eerste missie geslaagd.

http://www.brandsite.nl/circuitsonline/t_nijntje.jpg

Het koppelen van een tweede led matrix was daarna enorm eenvoudig.
Dit was enkel een kwestie van 100ohm weerstand van de TOTX van bord nummer 1 en 100ohm weerstand van de TORX van bord nummer twee
verwijderen en de TOTX van bord 1 aan de TORX van bord 2 koppelen.

http://www.brandsite.nl/circuitsonline/t_fds184_b.jpg

Via het schuifregister commando kun je nu ook het schuifregister van de andere borden tegelijkertijd aanspreken. Zie commando lijst:

http://www.brandsite.nl/circuitsonline/t_FDS184_10bitcommands.jpg

Schematische voorstelling van de FDS184 (De FDS185 heeft 1 segment meer) :

http://www.brandsite.nl/circuitsonline/t_fds184.jpg

En de code: (geschikt voor de XC compiler i.c.m Mplab X)

c code:


#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <xc.h>

// #pragma config statements should precede project file includes.
// Use project enums instead of #define for ON and OFF.
#define _XTAL_FREQ 16000000

// CONFIG1
#pragma config FOSC = INTOSC    // Oscillator Selection (INTOSC oscillator: I/O function on CLKIN pin)
#pragma config WDTE = OFF       // Watchdog Timer Enable (WDT disabled)
#pragma config PWRTE = OFF      // Power-up Timer Enable (PWRT disabled)
#pragma config MCLRE = ON       // MCLR Pin Function Select (MCLR/VPP pin function is MCLR)
#pragma config CP = OFF         // Flash Program Memory Code Protection (Program memory code protection is disabled)
#pragma config CPD = OFF        // Data Memory Code Protection (Data memory code protection is disabled)
#pragma config BOREN = ON       // Brown-out Reset Enable (Brown-out Reset enabled)
#pragma config CLKOUTEN = ON    // Clock Out Enable (CLKOUT function is enabled on the CLKOUT pin)
#pragma config IESO = ON        // Internal/External Switchover (Internal/External Switchover mode is enabled)
#pragma config FCMEN = ON       // Fail-Safe Clock Monitor Enable (Fail-Safe Clock Monitor is enabled)

// CONFIG2
#pragma config WRT = OFF        // Flash Memory Self-Write Protection (Write protection off)
#pragma config PLLEN = ON       // PLL Enable (4x PLL enabled)
#pragma config STVREN = ON      // Stack Overflow/Underflow Reset Enable (Stack Overflow or Underflow will cause a Reset)
#pragma config BORV = LO        // Brown-out Reset Voltage Selection (Brown-out Reset Voltage (Vbor), low trip point selected.)
#pragma config LVP = ON         // Low-Voltage Programming Enable (Low-voltage programming enabled)

#define LINE_SELECT  0x4004     // reversed 0x2A0. Should be 0x4005 but 0x400 seems to work as well. Which means that 0x220 should also werk in non reversed mode
#define SHIFT_ON     0xC0C0     // reversed 0x302: two displays on
#define SHIFT_OFF    0xC000     // reversed 0x300

#define NUM_VERT_UNITS   6                // we have 6x8 units on a FDS184 and 6x10 units on FDS185
#define NUM_HORI_UNITS   8                // we have 6x8 units on a FDS184 and 6x10 units on FDS185
#define NUM_SEGMENTS (NUM_HORI_UNITS / 2)
#define NUM_LINES_IN_SEGMENT 16

volatile uint8_t line_counter ;
uint16_t line;

#define SENDDATA8(c)  while(!TXIF);TXREG = ~c;
#define SENDDATA16(s) while(!TXIF);TXREG = ~(s >>8 );while(!TXIF);TXREG = ~(s & 0xFF);


static const uint8_t BitReverseTable256[] =  
{
  0x00, 0x80, 0x40, 0xC0, 0x20, 0xA0, 0x60, 0xE0, 0x10, 0x90, 0x50, 0xD0, 0x30, 0xB0, 0x70, 0xF0,
  0x08, 0x88, 0x48, 0xC8, 0x28, 0xA8, 0x68, 0xE8, 0x18, 0x98, 0x58, 0xD8, 0x38, 0xB8, 0x78, 0xF8,
  0x04, 0x84, 0x44, 0xC4, 0x24, 0xA4, 0x64, 0xE4, 0x14, 0x94, 0x54, 0xD4, 0x34, 0xB4, 0x74, 0xF4,
  0x0C, 0x8C, 0x4C, 0xCC, 0x2C, 0xAC, 0x6C, 0xEC, 0x1C, 0x9C, 0x5C, 0xDC, 0x3C, 0xBC, 0x7C, 0xFC,
  0x02, 0x82, 0x42, 0xC2, 0x22, 0xA2, 0x62, 0xE2, 0x12, 0x92, 0x52, 0xD2, 0x32, 0xB2, 0x72, 0xF2,
  0x0A, 0x8A, 0x4A, 0xCA, 0x2A, 0xAA, 0x6A, 0xEA, 0x1A, 0x9A, 0x5A, 0xDA, 0x3A, 0xBA, 0x7A, 0xFA,
  0x06, 0x86, 0x46, 0xC6, 0x26, 0xA6, 0x66, 0xE6, 0x16, 0x96, 0x56, 0xD6, 0x36, 0xB6, 0x76, 0xF6,
  0x0E, 0x8E, 0x4E, 0xCE, 0x2E, 0xAE, 0x6E, 0xEE, 0x1E, 0x9E, 0x5E, 0xDE, 0x3E, 0xBE, 0x7E, 0xFE,
  0x01, 0x81, 0x41, 0xC1, 0x21, 0xA1, 0x61, 0xE1, 0x11, 0x91, 0x51, 0xD1, 0x31, 0xB1, 0x71, 0xF1,
  0x09, 0x89, 0x49, 0xC9, 0x29, 0xA9, 0x69, 0xE9, 0x19, 0x99, 0x59, 0xD9, 0x39, 0xB9, 0x79, 0xF9,
  0x05, 0x85, 0x45, 0xC5, 0x25, 0xA5, 0x65, 0xE5, 0x15, 0x95, 0x55, 0xD5, 0x35, 0xB5, 0x75, 0xF5,
  0x0D, 0x8D, 0x4D, 0xCD, 0x2D, 0xAD, 0x6D, 0xED, 0x1D, 0x9D, 0x5D, 0xDD, 0x3D, 0xBD, 0x7D, 0xFD,
  0x03, 0x83, 0x43, 0xC3, 0x23, 0xA3, 0x63, 0xE3, 0x13, 0x93, 0x53, 0xD3, 0x33, 0xB3, 0x73, 0xF3,
  0x0B, 0x8B, 0x4B, 0xCB, 0x2B, 0xAB, 0x6B, 0xEB, 0x1B, 0x9B, 0x5B, 0xDB, 0x3B, 0xBB, 0x7B, 0xFB,
  0x07, 0x87, 0x47, 0xC7, 0x27, 0xA7, 0x67, 0xE7, 0x17, 0x97, 0x57, 0xD7, 0x37, 0xB7, 0x77, 0xF7,
  0x0F, 0x8F, 0x4F, 0xCF, 0x2F, 0xAF, 0x6F, 0xEF, 0x1F, 0x9F, 0x5F, 0xDF, 0x3F, 0xBF, 0x7F, 0xFF
};

uint8_t image_bits[NUM_VERT_UNITS * NUM_HORI_UNITS * 8] = {
/* byte 0             Line 0          |               Line 1              */
   0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x80,

   /*            Line 2               |               Line 3              */
   0x01, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x80,

   /*            ..                   |                   ..              */
   0x01, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x80,
   0x01, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x80,
   0x01, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x80,
   0x01, 0x80, 0x07, 0x80, 0x07, 0x80, 0x01, 0x40, 0x08, 0x40, 0x08, 0x80,
   0x01, 0x40, 0x10, 0x20, 0x08, 0x80, 0x01, 0x60, 0x20, 0x10, 0x18, 0x80,
   0x01, 0x20, 0x20, 0x10, 0x10, 0x80, 0x01, 0x20, 0x40, 0x08, 0x10, 0x80,
   0x01, 0x20, 0x40, 0x08, 0x10, 0x80, 0x01, 0x20, 0x40, 0x08, 0x10, 0x80,
   0x01, 0x20, 0x40, 0x08, 0x10, 0x80, 0x01, 0x20, 0x40, 0x08, 0x10, 0x80,
   0x01, 0x20, 0x40, 0x08, 0x10, 0x80, 0x01, 0x20, 0xc0, 0x0c, 0x10, 0x80,
   0x01, 0x20, 0x80, 0x04, 0x10, 0x80, 0x01, 0x60, 0x80, 0x04, 0x18, 0x80,
   0x01, 0x40, 0x80, 0x04, 0x08, 0x80, 0x01, 0x40, 0x80, 0x04, 0x08, 0x80,
   0x01, 0x40, 0x80, 0x04, 0x08, 0x80, 0x01, 0x80, 0x80, 0x04, 0x04, 0x80,
   0x01, 0x80, 0x80, 0x07, 0x04, 0x80, 0x01, 0x80, 0x00, 0x00, 0x04, 0x80,
   0x01, 0x00, 0x01, 0x00, 0x02, 0x80, 0x01, 0xc0, 0x00, 0x00, 0x0c, 0x80,
   0x01, 0x20, 0x00, 0x00, 0x10, 0x80, 0x01, 0x10, 0x00, 0x00, 0x20, 0x80,
   0x01, 0x08, 0x00, 0x00, 0x40, 0x80, 0x01, 0x0c, 0x00, 0x00, 0xc0, 0x80,
   0x01, 0x04, 0x00, 0x00, 0x80, 0x80, 0x01, 0x02, 0x00, 0x00, 0x00, 0x81,
   0x01, 0x02, 0x00, 0x00, 0x00, 0x81, 0x01, 0x02, 0x00, 0x00, 0x00, 0x81,
   0x01, 0x01, 0x00, 0x00, 0x00, 0x82, 0x01, 0x01, 0x00, 0x00, 0x00, 0x82,
   0x01, 0x01, 0x00, 0x00, 0x00, 0x82, 0x01, 0x01, 0x00, 0x00, 0x00, 0x82,
   0x01, 0x01, 0x03, 0x00, 0x03, 0x82, 0x01, 0x02, 0x03, 0x00, 0x03, 0x81,
   0x01, 0x02, 0x00, 0x00, 0x00, 0x81, 0x01, 0x02, 0x00, 0x00, 0x00, 0x81,
   0x01, 0x04, 0x00, 0x00, 0x80, 0x80, 0x01, 0x04, 0x00, 0x00, 0x80, 0x80,
   0x01, 0x08, 0x80, 0x04, 0x40, 0x80, 0x01, 0x10, 0x00, 0x03, 0x20, 0x80,
   0x01, 0x60, 0x80, 0x04, 0x18, 0x80, 0x01, 0x80, 0x01, 0x00, 0x06, 0x80,
   0x01, 0x00, 0x06, 0x80, 0x01, 0x80, 0x01, 0x00, 0xf8, 0x7f, 0x00, 0x80,
   0x01, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x80,
   0x01, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x80,
   0x01, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x80,
   0x01, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x80 };

int main(int argc, char** argv)
{
    /* Set Oscillator stuff */
    OSCCON = 0b01111011;         // switch to internal 16Mhz clock. HF
    while(!HFIOFR){RA2 = ~RA2;}; // Wait until High Freq Osc. is ready

    ANSELA = 0;  // no adc at the moment
    ANSELB = 0;  // no adc at the moment

    TRISA2 = 0; // Set RA2 output for debug purposes
    RA2 = 1;  // signal we're alive
    __delay_ms(1000);
    RA2 = 0;

    // EUSART stuff
    BRG16 = 0;  // 8 bit baud rate generator
    BRGH = 1;   // don't care in sync mode
    SPBRG = 0; // FOSc / 4 = max speed

    SYNC = 1;   // Set UART sync mode
    CSRC = 1;   // Set Master mode
    SREN = 0;   // set transmit mode
    CREN = 0;   // set transmit mode
    SCKP = 0;   // clock idle is low state
    SPEN = 1;   // Enable EUSART
    GIE = 1;    // enable global interrupts
    //PEIE = 1;   // enable peripheral interrupt
    TXIE = 0;
    TXEN = 1;   // enable transmit mode

    RXDTSEL = 0; //0 = RX/DT function is on RB1, 1 = RX/DT function is on RB2
    TXCKSEL = 0; //0 = TX/CK function is on RB2, 1 = TX/CK function is on RB5
    // End of EUSART stuff

    // Timer stuff
    PSA = 0;  // use prescaler for Timer0
    PS0 = 1;  // prescaler 64
    PS1 = 0;  // prescaler 64
    PS2 = 1;  // prescaler 64
    T0CS = 0; // timer input is Fosc/4
    TMR0IE = 1; // 
    // end of timer stuff

    RA2 = 0;
  
    while (1)
    {
           
    }
    return (EXIT_SUCCESS);
}

void interrupt   tc_int  (void)        // interrupt function
{
    if (TMR0IF)
    {       
        uint8_t *vp = (uint8_t*) image_bits + (NUM_VERT_UNITS*line_counter) ;

        for (uint8_t segment_counter = 0; segment_counter < NUM_SEGMENTS; segment_counter++)
        {
            for (uint8_t i=0; i<NUM_VERT_UNITS;i++)
            {
                    uint8_t b = vp[i];                  // get byte from video ram/rom
                    for (uint8_t j = 0; j< 8; j++)      // 8 bits in a byte
                    {                 
                            if (b & 0x01){
                                SENDDATA16(SHIFT_ON);}  // shitft bit high into shift register
                            else{
                                SENDDATA16(SHIFT_OFF);} // shift bit low into shift register
                            b >>= 1;
                    }
            }
            vp += (NUM_VERT_UNITS*16);      // Go to next segment in 'videoram/rom'. 2 rows of 8 bits in a segment.
        }

        // enable corresponding line in each segment
        line = LINE_SELECT | (BitReverseTable256[line_counter]);      
        SENDDATA16(line);        
           
        if (line_counter == (NUM_LINES_IN_SEGMENT-1)) { line_counter = 0;} // Lines can be 0-15. Set to 0 if we just updated line 15
        else {  line_counter += 1;}                     // increase line number
        TMR0IF = 0;                                     // clear TMR0 interrupt flag
        TMR0 = 0xff;                                    // restart timer
    }
}

Het hele verhaal hierboven is op dit moment een redelijke braindump van alles waar in tegen aan ben gelopen en die ik even snel op papier heb gezet. Er zullen ongetwijfeld nog fouten e.d inzitten.. Ik hoor het graag :))

De Datasheet

Hier een scope plot van het commando 'activate line 1' : 0x02A1

http://www.brandsite.nl/circuitsonline/activate_line_1.jpg

Een issue die nog opgelost moet worden is die van het dimmen en helder laten oplichten van het display. Ik heb wel een soort van methode gevonden maar ben nog steeds opzoek naar een commando dat goed en stabiel werkt.. Iemand dat dat misschien weet?

Verdere op en/of aanmerkingen hoor ik graag.

Groeten,
Sjoerd

Leuk dat je dat voor alle bezitters van zo'n scherm netjes in dit topic samenvat.

Even wat off-topic, maar toch ingaand op jouw verhaal:

.. 16LFxxx type te zijn waarbij het voltage tot max 3.Xxv ...

Volgens mij is een LF gewoon een geselecteerde F die het in de fabriek ook op 3.3V bleek te doen en mag je hem dus gerust op 5V gebruiken.

..waarbij ik niet het risico wilde lopen dat de FDS184 die 3.xx op de RX niet opvangt..

Zelfs als je hem met 3.3V voedt, dan komen die uitgangen nog ruim binnen TTL specs, dus die FDS18x zou er geen last van moeten hebben als je het mij vraagt.

Ik begrijp dat je inmiddels voor een andere PIC hebt gekozen, maar wat extra kennis is nooit verkeerd, toch?

If you want to succeed, double your failure rate.

Op 23 september 2014 08:11:47 schreef Jochem:
Leuk dat je dat voor alle bezitters van zo'n scherm netjes in dit topic samenvat.

Even wat off-topic, maar toch ingaand op jouw verhaal:[...]Volgens mij is een LF gewoon een geselecteerde F die het in de fabriek ook op 3.3V bleek te doen en mag je hem dus gerust op 5V gebruiken.

[...]Zelfs als je hem met 3.3V voedt, dan komen die uitgangen nog ruim binnen TTL specs, dus die FDS18x zou er geen last van moeten hebben als je het mij vraagt.

Ik begrijp dat je inmiddels voor een andere PIC hebt gekozen, maar wat extra kennis is nooit verkeerd, toch?

Bedankt voor je feedback.

Als ik een datasheet er bij pak dit zie ik dit bij de generieke specificaties:

1.8V-5.5V Operation – PIC16F1847
1.8V-3.6V Operation – PIC16LF1847

en bij Absolute Maximum Ratings
PIC16F1847: -0.3V to +6.5V
PIC16LF1847: -0.3V to +4.0V

Het lijkt me dan niet verstandig om deze LF op 5V te voeden toch?

Maar wel goed om te lezen dat 3.3V nog wel binnen de de TTL spec valt als het gaat om een HOOG signaal (Net even opgezocht, VOH = 2.4 V).

Achteraf was het dus wel mogelijk geweest om een LF pic te kiezen :)

Op 23 september 2014 08:30:07 schreef sjoerdb:
Als ik een datasheet er bij pak dit zie ik dit bij de generieke specificaties:

1.8V-5.5V Operation – PIC16F1847
1.8V-3.6V Operation – PIC16LF1847

en bij Absolute Maximum Ratings
PIC16F1847: -0.3V to +6.5V
PIC16LF1847: -0.3V to +4.0V

Het lijkt me dan niet verstandig om deze LF op 5V te voeden toch?

Dan heb je helemaal gelijk, de datasheet laat geen ruimte voor een andere interpretatie. En aan de minimum-spanning te zien, lijkt het bijna wel of de 16F* juist de selectie is die tijdens de productie eruit wordt gepikt, want beiden kunnen ze tot 1.8V werken.

Ik heb even geen tijd om het op te zoeken, maar ik weet eigenlijk zeker dat ik PIC16LF's van een ander type heb gehad die (ook) gewoon op 5V konden draaien.

edit: toch een voorbeeld gevonden

pag 165 datasheet PIC16F88
16LF88: 2.0-5.5V
16F88: 4.0-5.5V

Daar is het dus juist zo dat de LF het ruimere bereik heeft (en de F niet onder de 4V kan).

If you want to succeed, double your failure rate.

Raar maar waar.. als ik het 8 bits commando 0x21 stuur voor en na het 'line' commando (0x2A0) dan blijft het paneel fel opgelicht:

c code:


        SENDDATA8(0x21);

        // enable corresponding line in each segment
        line = LINE_SELECT |(BitReverseTable256[line_counter]);      
        SENDDATA16(line);

        SENDDATA8(0x21);  

Volgende stap is om te kijken of het display op een hogere frequentie (bijvoorbeeld 32Mhz) wil draaien aangezien ik de huidige update frequentie net niet acceptabel vindt.

Hee, gaaf dat je hiermee bezig bent en het beschikbaar maakt voor anderen op het forum.
Ik ben er ook bezig geweest om het met CPLD aan de praat te krijgen. Het lukte niet en de displays liggen nu te verstoffen 'op zolder'.
Nu kan ik het weer oppakken.

Ik had de klok voor de PIC afgetapt van het CPLD-kristal. Ik meen dat dat wat hoger was dan 16 MHz. Misschien kan je dat eens proberen?

Baco Army Goods heeft nu ook nog andere LED matrix panelen in de aanbieding zag ik toevallig: http://www.baco-army-goods.nl/index.php/catalogsearch/result/?q=led+ma…

Op 24 september 2014 07:21:36 schreef Zonnepaneeltje:

Ik had de klok voor de PIC afgetapt van het CPLD-kristal. Ik meen dat dat wat hoger was dan 16 MHz. Misschien kan je dat eens proberen?

Gebruik je dan CLKOUT of CLKR (Reference clock)?
CLKOUT is Fosc / 4 wat dus te langzaam is.
Kun je CLKR op Fosc zetten met CLKRDIV op 0? Als dat kan is dat ideaal om mee te testen.

Ik gebruikte de PIC18F26K22, die heeft een 4x PLL.

verkeerde knop.

@Moderator, dit bericht mag weg

[Bericht gewijzigd door sjoerdb op woensdag 24 september 2014 21:02:46 (90%)

Het lijkt niet te werken met de PIC16F1847 op 32Mhz en de clock rechtstreeks naar de FDS-184. Op 16Mhz werkt die constructie wel dus ik vermoed dat 32Mhz toch iets teveel van het goede is.

Nu draai ik met de PIC op 32Mhz en met een baudrate van Fosc / 8 naar de FDS-184.
Voordeel daarvan is dat de interrupt routine wat vlotter doorloopt t.o.v 16Mhz waardoor er een hogere en acceptabele framerate te halen is. Er is zelfs nog wat cpu tijd over om iets nuttigs te doen :)

Even een update. Net wat stof van de panelen geblazen en er weer even opnieuw naar gekeken. Interrupt doet nu een geheel frame per keer.
Dit voorkomt wat rare glitches zo nu en dan.

Verder heb ik het opgegeven om te achterhalen hoe het scherm gedimd en helder gezet kan worden maar heb ik X27 en X31 van de CPLD los gehaald en de beide G2A's van de 74HC238 aan ground gehangen zodat het paneel altijd helder is. Je kunt de G2A input ook aan een geïnverteerde PWM hangen zodat je zelf de helderheid kan regelen. Voor nu vind ik het prima :)

De iets aangepaste ISR die nu dus een geheel frame output:
(Blijkbaar heb ik nog wel wat delays nodig na iedere shift.. anders bakt het display er niks van)

c code:


if (TMR0IF)
    {
       for (line_counter = 0;line_counter < NUM_LINES_IN_SEGMENT;line_counter++)
       {
        uint8_t *vp1 = (uint8_t*) disp_buffer  + (NUM_VERT_UNITS*line_counter*NUM_DISPLAYS) ;
        for (segment_counter = 0; segment_counter < NUM_SEGMENTS; segment_counter++)
        {
            for (unit_counter=0; unit_counter<NUM_VERT_UNITS;unit_counter++)
            {
                    uint8_t b1 = *(vp1 + unit_counter);                        // get byte from video ram disp 1
                    uint8_t b2 = *(vp1 + unit_counter + NUM_VERT_UNITS);       // get byte from video ram disp 2
                    uint8_t b3 = *(vp1 + unit_counter + (NUM_VERT_UNITS * 2));       // get byte from video ram disp 2

                    if (b1 & 0x1){shiftvalue = 0x80;}else {shiftvalue = 0;}if (b2 & 0x1){shiftvalue |= 0x40;}if (b3 & 0x1){shiftvalue |= 0x20;}SENDDATA16(0xC000 | shiftvalue);__delay_us(5);
                    if (b1 & 0x2){shiftvalue = 0x80;}else {shiftvalue = 0;}if (b2 & 0x2){shiftvalue |= 0x40;}if (b3 & 0x2){shiftvalue |= 0x20;}SENDDATA16(0xC000 | shiftvalue);__delay_us(5);
                    if (b1 & 0x4){shiftvalue = 0x80;}else {shiftvalue = 0;}if (b2 & 0x4){shiftvalue |= 0x40;}if (b3 & 0x4){shiftvalue |= 0x20;}SENDDATA16(0xC000 | shiftvalue);__delay_us(5);
                    if (b1 & 0x8){shiftvalue = 0x80;}else {shiftvalue = 0;}if (b2 & 0x8){shiftvalue |= 0x40;}if (b3 & 0x8){shiftvalue |= 0x20;}SENDDATA16(0xC000 | shiftvalue);__delay_us(5);
                    if (b1 & 0x10){shiftvalue = 0x80;}else {shiftvalue = 0;}if (b2 & 0x10){shiftvalue |= 0x40;}if (b3 & 0x10){shiftvalue |= 0x20;}SENDDATA16(0xC000 | shiftvalue);__delay_us(5);
                    if (b1 & 0x20){shiftvalue = 0x80;}else {shiftvalue = 0;}if (b2 & 0x20){shiftvalue |= 0x40;}if (b3 & 0x20){shiftvalue |= 0x20;}SENDDATA16(0xC000 | shiftvalue);__delay_us(5);
                    if (b1 & 0x40){shiftvalue = 0x80;}else {shiftvalue = 0;}if (b2 & 0x40){shiftvalue |= 0x40;}if (b3 & 0x40){shiftvalue |= 0x20;}SENDDATA16(0xC000 | shiftvalue);__delay_us(5);
                    if (b1 & 0x80){shiftvalue = 0x80;}else {shiftvalue = 0;}if (b2 & 0x80){shiftvalue |= 0x40;}if (b3 & 0x80){shiftvalue |= 0x20;}SENDDATA16(0xC000 | shiftvalue);__delay_us(5);

                   // SENDDATA16(0xC0E0);
                
            }
            vp1 += (NUM_VERT_UNITS*16*NUM_DISPLAYS);      // Go to next segment in 'videoram/rom'. 2 rows of 8 bits in a segment.
        }

        // enable corresponding line in each segment        
        line = LINE_SELECT | (*(BitReverseTable256 + line_counter));
        SENDDATA16(line);
        __delay_us(10);
       }
      
       
      TMR0IF = 0;                                     // clear TMR0 interrupt flag
      TMR0 = 0xc0;                                    // restart timer
        
    }