/ MCUME_pico / display / pico_dsp.cpp
pico_dsp.cpp
   1  /*
   2  	This file is part of DISPLAY library. 
   3    Supports VGA and TFT display
   4  
   5  	DISPLAY library is free software: you can redistribute it and/or modify
   6  	it under the terms of the GNU General Public License as published by
   7  	the Free Software Foundation, either version 3 of the License, or
   8  	(at your option) any later version.
   9  
  10  	Copyright (C) 2020 J-M Harvengt
  11  */
  12  
  13  #include "pico/stdlib.h"
  14  #include "pico/multicore.h"
  15  #include "hardware/spi.h"
  16  #include "hardware/dma.h"
  17  #include "hardware/irq.h"
  18  #include <string.h>
  19  
  20  #include "PICO_DSP.h"
  21  #include "font8x8.h"
  22  #include "include.h"
  23  
  24  static gfx_mode_t gfxmode = MODE_UNDEFINED;
  25  
  26  /* TFT structures / constants */
  27  #define digitalWrite(pin, val) gpio_put(pin, val)
  28  
  29  #define SPICLOCK 60000000 
  30  #ifdef USE_VGA
  31  #define SPI_MODE SPI_CPOL_1 
  32  #else
  33  #ifdef ST7789
  34  #ifdef ST7789_POL
  35  #define SPI_MODE SPI_CPOL_0
  36  #else
  37  #define SPI_MODE SPI_CPOL_1
  38  #endif
  39  #endif
  40  #ifdef ILI9341
  41  #define SPI_MODE SPI_CPOL_0
  42  #endif
  43  #endif
  44  
  45  #define LINES_PER_BLOCK  64
  46  #define NR_OF_BLOCK      4
  47  
  48  #define TFT_SWRESET    0x01
  49  #define TFT_SLPOUT     0x11
  50  #define TFT_INVON      0x21
  51  #define TFT_DISPOFF    0x28
  52  #define TFT_DISPON     0x29
  53  #define TFT_CASET      0x2A
  54  #define TFT_PASET      0x2B
  55  #define TFT_RAMWR      0x2C
  56  #define TFT_MADCTL     0x36
  57  #define TFT_PIXFMT     0x3A
  58  #define TFT_MADCTL_MY  0x80
  59  #define TFT_MADCTL_MX  0x40
  60  #define TFT_MADCTL_MV  0x20
  61  #define TFT_MADCTL_ML  0x10
  62  #define TFT_MADCTL_RGB 0x00
  63  #define TFT_MADCTL_BGR 0x08
  64  #define TFT_MADCTL_MH  0x04
  65  
  66  static void SPItransfer(uint8_t val)
  67  {
  68    uint8_t dat8=val;
  69    spi_write_blocking(TFT_SPIREG, &dat8, 1);
  70  }
  71  
  72  static void SPItransfer16(uint16_t val)
  73  {
  74    uint8_t dat8[2];
  75    dat8[0] = val>>8;
  76    dat8[1] = val&0xff;
  77    spi_write_blocking(TFT_SPIREG, dat8, 2);
  78  }
  79  
  80  #define DELAY_MASK     0x80
  81  static const uint8_t init_commands[] = { 
  82    1+DELAY_MASK, TFT_SWRESET,  150,
  83    1+DELAY_MASK, TFT_SLPOUT,   255,
  84    2+DELAY_MASK, TFT_PIXFMT, 0x55, 10,
  85    2,            TFT_MADCTL, TFT_MADCTL_MV | TFT_MADCTL_BGR,
  86    1, TFT_INVON,
  87    1, TFT_DISPON,
  88    0
  89  };
  90  
  91  /* TFT structures / constants */
  92  #define RGBVAL16(r,g,b)  ( (((r>>3)&0x1f)<<11) | (((g>>2)&0x3f)<<5) | (((b>>3)&0x1f)<<0) )
  93  
  94  static uint16_t * blocks[NR_OF_BLOCK];
  95  static uint16_t blocklens[NR_OF_BLOCK];
  96  static dma_channel_config dmaconfig;
  97  static uint dma_tx=0;
  98  static volatile uint8_t rstop = 0;
  99  static volatile bool cancelled = false;
 100  static volatile uint8_t curTransfer = 0;
 101  static uint8_t nbTransfer = 0;
 102  
 103  /* VGA structures / constants */
 104  #define R16(rgb) ((rgb>>8)&0xf8) 
 105  #define G16(rgb) ((rgb>>3)&0xfc) 
 106  #define B16(rgb) ((rgb<<3)&0xf8) 
 107  #ifdef VGA222
 108  #define VGA_RGB(r,g,b)   ( (((r>>6)&0x03)<<4) | (((g>>6)&0x03)<<2) | (((b>>6)&0x3)<<0) )
 109  #else
 110  #define VGA_RGB(r,g,b)   ( (((r>>5)&0x07)<<5) | (((g>>5)&0x07)<<2) | (((b>>6)&0x3)<<0) )
 111  #endif
 112  
 113  // 8 bits 320x240 frame buffer => 64K
 114  static vga_pixel * visible_framebuffer = NULL;
 115  static vga_pixel * framebuffer = NULL;
 116  static vga_pixel * fb0 = NULL;
 117  static vga_pixel * fb1 = NULL;
 118  
 119  static int  fb_width;
 120  static int  fb_height;
 121  static int  fb_stride;
 122  
 123  static const sVmode* vmode=NULL;
 124  static const sVmode* volatile VgaVmodeReq = NULL; // request to reinitialize videomode, 1=only stop driver
 125  
 126  static semaphore_t core1_initted;
 127  static void core1_func();
 128  static void core1_sio_irq();
 129  static void VgaInitReql(const sVmode* vmode)
 130  {
 131    if (vmode == NULL) vmode = (const sVmode*)1;
 132    __dmb();
 133    VgaVmodeReq = vmode;
 134    while (VgaVmodeReq != NULL) { __dmb(); }
 135  }
 136  
 137  static void core1_func()
 138  {
 139    const sVmode* v;
 140  
 141    multicore_fifo_clear_irq();
 142    irq_set_exclusive_handler(SIO_IRQ_PROC1,core1_sio_irq);
 143    //irq_set_priority (SIO_IRQ_PROC1, 129);    
 144    irq_set_enabled(SIO_IRQ_PROC1,true);
 145  
 146    sem_release(&core1_initted);
 147   
 148    while (true)
 149    {
 150      __dmb();
 151  
 152      // initialize videomode
 153      v = VgaVmodeReq;
 154      if (v != NULL)
 155      {
 156        if ((u32)v == (u32)1) {
 157          //VgaTerm(); // terminate
 158        }
 159        else
 160          VgaInit(v,(u8*)framebuffer,320,240,320);
 161        __dmb();
 162        VgaVmodeReq = NULL;
 163      }
 164    }
 165  }
 166  
 167  
 168  void PICO_DSP::setArea(uint16_t x1,uint16_t y1,uint16_t x2,uint16_t y2) {
 169    int dx=0;
 170    int dy=0;
 171  #ifdef ST7789
 172    if (TFT_REALWIDTH == TFT_REALHEIGHT)
 173    {
 174  #ifdef ROTATE_SCREEN
 175      if (!flipped) {
 176        dy += 80;    
 177      }
 178  #else  
 179      if (flipped) {
 180        dx += 80;    
 181      }
 182  #endif      
 183    }
 184  #endif  
 185  
 186    digitalWrite(_dc, 0);
 187    SPItransfer(TFT_CASET);
 188    digitalWrite(_dc, 1);
 189    SPItransfer16(x1+dx);
 190    digitalWrite(_dc, 1);
 191    SPItransfer16(x2+dx);  
 192    digitalWrite(_dc, 0);
 193    SPItransfer(TFT_PASET);
 194    digitalWrite(_dc, 1);
 195    SPItransfer16(y1+dy);
 196    digitalWrite(_dc, 1);
 197    SPItransfer16(y2+dy);  
 198  
 199    digitalWrite(_dc, 0);
 200    SPItransfer(TFT_RAMWR);
 201    digitalWrite(_dc, 1);
 202   
 203    return; 
 204  }
 205  
 206  
 207  PICO_DSP::PICO_DSP()
 208  {
 209  }
 210  
 211  gfx_error_t PICO_DSP::begin(gfx_mode_t mode)
 212  {
 213    switch(mode) {
 214      case MODE_VGA_320x240:
 215        // Reset SPI if we come from TFT mode
 216        if (gfxmode == MODE_TFT_320x240) {
 217          fillScreenNoDma(RGBVAL16(0x0,0x00,0x00));
 218          digitalWrite(_cs, 0);
 219          digitalWrite(_dc, 0);
 220          SPItransfer(TFT_DISPOFF);
 221          digitalWrite(_cs, 1);
 222          sleep_ms(20);
 223          digitalWrite(_cs, 0);
 224          digitalWrite(_cs, 1);
 225          if (_bkl != 0xff) {
 226            digitalWrite(_bkl, 0);
 227          }
 228          //spi_init(TFT_SPIREG, 0);
 229          //spi_deinit(TFT_SPIREG);
 230          //spi_set_slave(TFT_SPIREG, true);
 231        }  
 232        gfxmode = mode;
 233        fb_width = 320;
 234        fb_height = 240;      
 235        fb_stride = fb_width;
 236        /* initialize gfx buffer */
 237        if (fb0 == NULL) {
 238          void *mallocpt = malloc(fb_stride*fb_height*sizeof(vga_pixel)+4);    
 239          fb0 = (vga_pixel *)((void*)((intptr_t)mallocpt & ~3));
 240        }
 241        visible_framebuffer = fb0;
 242        framebuffer = fb0;
 243        for (uint i = 0; i < fb_height*fb_width; i++) {
 244          framebuffer[i] = VGA_RGB(rand() % 255,rand() % 255,rand() % 255);      
 245        }
 246        // create a semaphore to be posted when audio init is complete
 247        sem_init(&core1_initted, 0, 1);
 248        multicore_launch_core1(core1_func);
 249        vmode = Video(DEV_VGA, RES_QVGA);
 250        VgaInitReql(vmode);
 251        // wait for initialization of audio to be complete
 252        sem_acquire_blocking(&core1_initted);      
 253        break;
 254  
 255      case MODE_TFT_320x240:
 256        gfxmode = mode;
 257        fb_width = TFT_WIDTH;
 258        fb_height = TFT_HEIGHT;      
 259        fb_stride = fb_width;    
 260        _cs   = TFT_CS;
 261        _dc   = TFT_DC;
 262        _rst  = TFT_RST;
 263        _mosi = TFT_MOSI;
 264        _sclk = TFT_SCLK;
 265        _bkl = TFT_BACKLIGHT;
 266        gpio_init(_dc);
 267        gpio_set_dir(_dc, GPIO_OUT); 
 268        gpio_init(_cs);
 269        gpio_set_dir(_cs, GPIO_OUT);
 270        digitalWrite(_cs, 1);
 271        digitalWrite(_dc, 1);
 272        if (_bkl != 0xff) {
 273          gpio_init(_bkl);
 274          gpio_set_dir(_bkl, GPIO_OUT); 
 275          digitalWrite(_bkl, 1);
 276        } 
 277  
 278        spi_init(TFT_SPIREG, SPICLOCK);
 279        spi_set_format(TFT_SPIREG, 8, SPI_MODE, SPI_CPHA_0, SPI_MSB_FIRST);
 280        gpio_set_function(_sclk , GPIO_FUNC_SPI);
 281        gpio_set_function(_mosi , GPIO_FUNC_SPI);
 282           
 283        // Initialize display
 284        if (_rst != 0xff) {
 285          gpio_init(_rst);
 286          gpio_set_dir(_rst, GPIO_OUT);     
 287          digitalWrite(_rst, 1);
 288          sleep_ms(100);
 289          digitalWrite(_rst, 0);
 290          sleep_ms(100);
 291          digitalWrite(_rst, 1);
 292          sleep_ms(200);
 293        }
 294        const uint8_t *addr = init_commands;
 295        uint8_t count;
 296        digitalWrite(_cs, 0);
 297        while (count = *addr++) {
 298          uint8_t command = *addr++;
 299  #ifdef ILI9341
 300          if ( command == TFT_INVON ) {
 301            // Skip TFT_INVON for ILI
 302          }
 303          else 
 304  #endif
 305          {
 306            digitalWrite(_dc, 0); // command
 307            SPItransfer(command);
 308            uint16_t ms = count & DELAY_MASK;
 309            count &= ~DELAY_MASK;
 310            while (--count > 0) { // data
 311              uint8_t data = *addr++;
 312  #ifdef ILI9341
 313  #else
 314              if ( command == TFT_MADCTL ) {
 315                data = TFT_MADCTL_MX | TFT_MADCTL_MV |TFT_MADCTL_RGB;
 316              }
 317  #endif
 318              digitalWrite(_dc, 1);
 319              SPItransfer(data);
 320            }
 321            if (ms) {
 322              ms = *addr++; // Read post-command delay time (ms)
 323              if(ms == 255) ms = 500;   // If 255, delay for 500 ms
 324              digitalWrite(_cs, 1);
 325              //SPI.endTransaction();
 326              sleep_ms(ms);
 327              //SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE));
 328              digitalWrite(_cs, 0);      
 329            }     
 330          }
 331        }
 332        digitalWrite(_cs, 1);
 333        break;
 334    }	
 335  
 336  
 337    return(GFX_OK);
 338  }
 339  
 340  void PICO_DSP::end()
 341  {
 342  }
 343  
 344  gfx_mode_t PICO_DSP::getMode(void)
 345  {
 346    return gfxmode;
 347  }
 348  
 349  void PICO_DSP::flipscreen(bool flip)
 350  {
 351    digitalWrite(_dc, 0);
 352    digitalWrite(_cs, 0);
 353    SPItransfer(TFT_MADCTL);
 354    digitalWrite(_dc, 1);
 355    if (flip) {
 356      flipped=true;
 357  
 358  #ifdef ILI9341         
 359      SPItransfer(TFT_MADCTL_MV | TFT_MADCTL_BGR);
 360  #endif
 361  #ifdef ST7789
 362  #ifdef ROTATE_SCREEN
 363      SPItransfer(TFT_MADCTL_RGB);
 364  #else
 365      SPItransfer(TFT_MADCTL_MY | TFT_MADCTL_MV |TFT_MADCTL_RGB);
 366  #endif
 367  #endif 
 368    }
 369    else {
 370      flipped=false;
 371     
 372  #ifdef ILI9341        
 373      SPItransfer(TFT_MADCTL_MX | TFT_MADCTL_MY | TFT_MADCTL_MV | TFT_MADCTL_BGR);
 374  #endif
 375  #ifdef ST7789
 376  #ifdef ROTATE_SCREEN
 377      SPItransfer(TFT_MADCTL_MX | TFT_MADCTL_MY | TFT_MADCTL_RGB);
 378  #else
 379      SPItransfer(TFT_MADCTL_MX | TFT_MADCTL_MV | TFT_MADCTL_RGB);
 380  #endif
 381  #endif  
 382    }
 383    digitalWrite(_cs, 1);   
 384  }
 385  
 386  
 387  bool PICO_DSP::isflipped(void)
 388  {
 389    return(flipped);
 390  }
 391    
 392  
 393  /***********************************************************************************************
 394      DMA functions
 395   ***********************************************************************************************/
 396  static void dma_isr() { 
 397    irq_clear(DMA_IRQ_0);
 398    dma_hw->ints0 = 1u << dma_tx;
 399    curTransfer++;
 400    if (curTransfer >= nbTransfer) {
 401      curTransfer = 0;
 402    }
 403    if (cancelled) {
 404      rstop = 1;
 405    }
 406    else 
 407    {
 408      dma_channel_transfer_from_buffer_now(dma_tx, blocks[curTransfer], blocklens[curTransfer]);
 409    }  
 410  }
 411  
 412  static void setDmaStruct() {
 413    // Setup the control channel
 414    if (dma_tx == 0)  {
 415      dma_tx = dma_claim_unused_channel(true);
 416    }    
 417    dmaconfig = dma_channel_get_default_config(dma_tx);
 418    channel_config_set_transfer_data_size(&dmaconfig, DMA_SIZE_16);
 419    channel_config_set_dreq(&dmaconfig, TFT_SPIDREQ);  
 420    //channel_config_set_read_increment(&dmaconfig, true); // read incrementing
 421    //channel_config_set_write_increment(&dmaconfig, false); // no write incrementing
 422  
 423    dma_channel_configure(
 424        dma_tx,
 425        &dmaconfig,
 426        &spi_get_hw(TFT_SPIREG)->dr, // write address
 427        blocks[0],
 428        blocklens[0],
 429        false
 430    ); 
 431  
 432    irq_set_exclusive_handler(DMA_IRQ_0, dma_isr);
 433    dma_channel_set_irq0_enabled(dma_tx, true);
 434    irq_set_enabled(DMA_IRQ_0, true);
 435    dma_hw->ints0 = 1u << dma_tx;  
 436  }
 437  
 438  void PICO_DSP::startRefresh(void) {
 439    if (gfxmode == MODE_TFT_320x240) {
 440      uint32_t remaining = TFT_HEIGHT*TFT_WIDTH*2;
 441      int i=0;
 442      nbTransfer = 0;
 443      while (remaining > 0) {
 444        uint16_t * fb = blocks[i];
 445        int32_t len = (remaining >= (LINES_PER_BLOCK*TFT_WIDTH*2)?LINES_PER_BLOCK*TFT_WIDTH*2:remaining);     
 446        switch (i) {
 447          case 0:
 448            if (fb == 0) fb = (uint16_t*)((int)malloc(len+64)&0xffffffe0);       
 449            break;
 450          case 1:
 451            if (fb == 0) fb = (uint16_t*)((int)malloc(len+64)&0xffffffe0);      
 452            break;
 453          case 2:
 454            if (fb == 0) fb = (uint16_t*)((int)malloc(len+64)&0xffffffe0);      
 455            break;
 456          case 3:
 457            if (fb == 0) fb = (uint16_t*)((int)malloc(len+64)&0xffffffe0);       
 458            break;
 459        }
 460        blocks[i] = fb;
 461        blocklens[i] = len/2;
 462        if (blocks[i] == 0) {
 463          fillScreenNoDma(RGBVAL16(0xFF,0xFF,0x00));
 464          printf("FB allocaltion failed for block %d\n",i);
 465          sleep_ms(10000);    
 466        }
 467        nbTransfer++;
 468        remaining -= len;    
 469        i++;
 470      }                
 471      curTransfer = 0;  
 472      rstop = 0;     
 473      digitalWrite(_cs, 1);
 474      setDmaStruct();
 475      fillScreen(RGBVAL16(0x00,0x00,0x00));
 476      digitalWrite(_cs, 0);
 477  
 478      setArea((TFT_REALWIDTH-TFT_WIDTH)/2, (TFT_REALHEIGHT-TFT_HEIGHT)/2, (TFT_REALWIDTH-TFT_WIDTH)/2 + TFT_WIDTH-1, (TFT_REALHEIGHT-TFT_HEIGHT)/2+TFT_HEIGHT-1);  
 479      // we switch to 16bit mode!!
 480      spi_set_format(TFT_SPIREG, 16, SPI_CPOL_0, SPI_CPHA_0, SPI_MSB_FIRST);
 481      dma_start_channel_mask(1u << dma_tx);    
 482    }
 483    else { 
 484      fillScreen(RGBVAL16(0x00,0x00,0x00));   
 485    }
 486  }
 487  
 488  void PICO_DSP::stopRefresh(void) {
 489    if (gfxmode == MODE_TFT_320x240) {
 490      rstop = 1;
 491      unsigned long m = time_us_32()*1000;   
 492      cancelled = true; 
 493      while (!rstop)  {
 494        if ((time_us_32()*1000 - m) > 100) break;
 495        sleep_ms(100);
 496        asm volatile("wfi");
 497      };
 498      rstop = 0;
 499      sleep_ms(100);
 500      cancelled = false;  
 501      //dmatx.detachInterrupt();
 502      fillScreen(RGBVAL16(0x00,0x00,0x00));
 503      digitalWrite(_cs, 1);
 504      // we switch back to GFX mode!!
 505      begin(gfxmode);
 506      setArea(0, 0, TFT_REALWIDTH-1, TFT_REALHEIGHT-1);    
 507    }
 508  }
 509  
 510  
 511  /***********************************************************************************************
 512      GFX functions
 513   ***********************************************************************************************/
 514  // retrieve size of the frame buffer
 515  int PICO_DSP::get_frame_buffer_size(int *width, int *height)
 516  {
 517    if (width != nullptr) *width = fb_width;
 518    if (height != nullptr) *height = fb_height;
 519    return fb_stride;
 520  }
 521  
 522  void PICO_DSP::waitSync()
 523  {
 524    if (gfxmode == MODE_TFT_320x240) {
 525    }
 526    else { 
 527      WaitVSync();
 528    }
 529  }
 530  
 531  void PICO_DSP::waitLine(int line)
 532  {
 533    if (gfxmode == MODE_TFT_320x240) {
 534    }
 535    else { 
 536  //  while (currentLine != line) {};
 537    }
 538  }
 539  
 540  
 541  /***********************************************************************************************
 542      GFX functions
 543   ***********************************************************************************************/
 544  /*
 545  vga_pixel * PICO_DSP::getLineBuffer(int j) {
 546    return (&framebuffer[j*fb_stride]);
 547  }
 548  */
 549  
 550  void PICO_DSP::fillScreen(dsp_pixel color) {
 551    int i,j;
 552    if (gfxmode == MODE_TFT_320x240) {
 553      for (j=0; j<TFT_HEIGHT; j++)
 554      {
 555        uint16_t * block=blocks[j>>6];
 556        uint16_t * dst=&block[(j&0x3F)*fb_stride];
 557        for (i=0; i<fb_width; i++)
 558        {
 559          *dst++ = color;
 560        }
 561      }
 562    }
 563    else {
 564      vga_pixel color8 = VGA_RGB(R16(color),G16(color),B16(color));
 565      for (j=0; j<fb_height; j++)
 566      {
 567        vga_pixel * dst=&framebuffer[j*fb_stride];
 568        for (i=0; i<fb_width; i++)
 569        {
 570          *dst++ = color8;
 571        }
 572      }    
 573    }  
 574  }
 575  
 576  void PICO_DSP::drawRect(int16_t x, int16_t y, int16_t w, int16_t h, dsp_pixel color) {
 577    int i,j,l=y;
 578    if (gfxmode == MODE_TFT_320x240) {
 579      for (j=0; j<h; j++)
 580      {
 581        uint16_t * block=blocks[l>>6];
 582        uint16_t * dst=&block[(l&0x3F)*fb_stride+x];
 583        for (i=0; i<w; i++)
 584        {
 585          *dst++ = color;
 586        }
 587        l++;
 588      }
 589    }
 590    else {
 591      vga_pixel color8 = VGA_RGB(R16(color),G16(color),B16(color));
 592      for (j=0; j<h; j++)
 593      {
 594        vga_pixel * dst=&framebuffer[l*fb_stride+x];
 595        for (i=0; i<w; i++)
 596        {
 597          *dst++ = color8;
 598        }
 599        l++;
 600      }
 601    }  
 602  }
 603  
 604  void PICO_DSP::drawText(int16_t x, int16_t y, const char * text, dsp_pixel fgcolor, dsp_pixel bgcolor, bool doublesize) {
 605    if (gfxmode == MODE_TFT_320x240) {
 606      uint16_t c;
 607      uint16_t * block;
 608      uint16_t * dst;
 609      fgcolor = fgcolor;
 610      bgcolor = bgcolor;
 611      while ((c = *text++)) {
 612        const unsigned char * charpt=&font8x8[c][0];
 613        int l=y;
 614        for (int i=0;i<8;i++)
 615        {     
 616          unsigned char bits;
 617          if (doublesize) {
 618            block=blocks[l>>6];
 619            dst=&block[(l&0x3F)*fb_stride+x];         
 620            bits = *charpt;     
 621            if (bits&0x01) *dst++=fgcolor;
 622            else *dst++=bgcolor;
 623            bits = bits >> 1;     
 624            if (bits&0x01) *dst++=fgcolor;
 625            else *dst++=bgcolor;
 626            bits = bits >> 1;     
 627            if (bits&0x01) *dst++=fgcolor;
 628            else *dst++=bgcolor;
 629            bits = bits >> 1;     
 630            if (bits&0x01) *dst++=fgcolor;
 631            else *dst++=bgcolor;
 632            bits = bits >> 1;     
 633            if (bits&0x01) *dst++=fgcolor;
 634            else *dst++=bgcolor;
 635            bits = bits >> 1;     
 636            if (bits&0x01) *dst++=fgcolor;
 637            else *dst++=bgcolor;
 638            bits = bits >> 1;     
 639            if (bits&0x01) *dst++=fgcolor;
 640            else *dst++=bgcolor;
 641            bits = bits >> 1;     
 642            if (bits&0x01) *dst++=fgcolor;
 643            else *dst++=bgcolor;
 644            l++;       
 645          }
 646          block=blocks[l>>6];
 647          dst=&block[(l&0x3F)*fb_stride+x]; 
 648          bits = *charpt++;     
 649          if (bits&0x01) *dst++=fgcolor;
 650          else *dst++=bgcolor;
 651          bits = bits >> 1;     
 652          if (bits&0x01) *dst++=fgcolor;
 653          else *dst++=bgcolor;
 654          bits = bits >> 1;     
 655          if (bits&0x01) *dst++=fgcolor;
 656          else *dst++=bgcolor;
 657          bits = bits >> 1;     
 658          if (bits&0x01) *dst++=fgcolor;
 659          else *dst++=bgcolor;
 660          bits = bits >> 1;     
 661          if (bits&0x01) *dst++=fgcolor;
 662          else *dst++=bgcolor;
 663          bits = bits >> 1;     
 664          if (bits&0x01) *dst++=fgcolor;
 665          else *dst++=bgcolor;
 666          bits = bits >> 1;     
 667          if (bits&0x01) *dst++=fgcolor;
 668          else *dst++=bgcolor;
 669          bits = bits >> 1;     
 670          if (bits&0x01) *dst++=fgcolor;
 671          else *dst++=bgcolor;
 672          l++;
 673        }
 674        x +=8;
 675      }  
 676    }
 677    else {
 678      vga_pixel fgcolor8 = VGA_RGB(R16(fgcolor),G16(fgcolor),B16(fgcolor));
 679      vga_pixel bgcolor8 = VGA_RGB(R16(bgcolor),G16(bgcolor),B16(bgcolor));
 680      vga_pixel c;
 681      vga_pixel * dst;
 682      while ((c = *text++)) {
 683        const unsigned char * charpt=&font8x8[c][0];
 684        int l=y;
 685        for (int i=0;i<8;i++)
 686        {     
 687          unsigned char bits;
 688          if (doublesize) {
 689            dst=&framebuffer[l*fb_stride+x];
 690            bits = *charpt;     
 691            if (bits&0x01) *dst++=fgcolor8;
 692            else *dst++=bgcolor8;
 693            bits = bits >> 1;     
 694            if (bits&0x01) *dst++=fgcolor8;
 695            else *dst++=bgcolor8;
 696            bits = bits >> 1;     
 697            if (bits&0x01) *dst++=fgcolor8;
 698            else *dst++=bgcolor8;
 699            bits = bits >> 1;     
 700            if (bits&0x01) *dst++=fgcolor8;
 701            else *dst++=bgcolor8;
 702            bits = bits >> 1;     
 703            if (bits&0x01) *dst++=fgcolor8;
 704            else *dst++=bgcolor8;
 705            bits = bits >> 1;     
 706            if (bits&0x01) *dst++=fgcolor8;
 707            else *dst++=bgcolor8;
 708            bits = bits >> 1;     
 709            if (bits&0x01) *dst++=fgcolor8;
 710            else *dst++=bgcolor8;
 711            bits = bits >> 1;     
 712            if (bits&0x01) *dst++=fgcolor8;
 713            else *dst++=bgcolor8;
 714            l++;
 715          }
 716          dst=&framebuffer[l*fb_stride+x]; 
 717          bits = *charpt++;     
 718          if (bits&0x01) *dst++=fgcolor8;
 719          else *dst++=bgcolor8;
 720          bits = bits >> 1;     
 721          if (bits&0x01) *dst++=fgcolor8;
 722          else *dst++=bgcolor8;
 723          bits = bits >> 1;     
 724          if (bits&0x01) *dst++=fgcolor8;
 725          else *dst++=bgcolor8;
 726          bits = bits >> 1;     
 727          if (bits&0x01) *dst++=fgcolor8;
 728          else *dst++=bgcolor8;
 729          bits = bits >> 1;     
 730          if (bits&0x01) *dst++=fgcolor8;
 731          else *dst++=bgcolor8;
 732          bits = bits >> 1;     
 733          if (bits&0x01) *dst++=fgcolor8;
 734          else *dst++=bgcolor8;
 735          bits = bits >> 1;     
 736          if (bits&0x01) *dst++=fgcolor8;
 737          else *dst++=bgcolor8;
 738          bits = bits >> 1;     
 739          if (bits&0x01) *dst++=fgcolor8;
 740          else *dst++=bgcolor8;
 741          l++;
 742        }
 743        x +=8;
 744      }
 745    }  
 746  }
 747  
 748  void PICO_DSP::drawSprite(int16_t x, int16_t y, const dsp_pixel *bitmap, uint16_t arx, uint16_t ary, uint16_t arw, uint16_t arh)
 749  {
 750    int bmp_offx = 0;
 751    int bmp_offy = 0;
 752    uint16_t *bmp_ptr;
 753    int w =*bitmap++;
 754    int h = *bitmap++;
 755    if ( (arw == 0) || (arh == 0) ) {
 756      // no crop window
 757      arx = x;
 758      ary = y;
 759      arw = w;
 760      arh = h;
 761    }
 762    else {
 763      if ( (x>(arx+arw)) || ((x+w)<arx) || (y>(ary+arh)) || ((y+h)<ary)   ) {
 764        return;
 765      }
 766      // crop area
 767      if ( (x > arx) && (x<(arx+arw)) ) { 
 768        arw = arw - (x-arx);
 769        arx = arx + (x-arx);
 770      } else {
 771        bmp_offx = arx;
 772      }
 773      if ( ((x+w) > arx) && ((x+w)<(arx+arw)) ) {
 774        arw -= (arx+arw-x-w);
 775      }  
 776      if ( (y > ary) && (y<(ary+arh)) ) {
 777        arh = arh - (y-ary);
 778        ary = ary + (y-ary);
 779      } else {
 780        bmp_offy = ary;
 781      }
 782      if ( ((y+h) > ary) && ((y+h)<(ary+arh)) ) {
 783        arh -= (ary+arh-y-h);
 784      }     
 785    }
 786    int l=ary;
 787    bitmap = bitmap + bmp_offy*w + bmp_offx;
 788  
 789  
 790    if (gfxmode == MODE_TFT_320x240) {
 791      for (int row=0;row<arh; row++)
 792      {
 793        uint16_t * block=blocks[l>>6];
 794        uint16_t * dst=&block[(l&0x3F)*fb_stride+arx];  
 795        bmp_ptr = (uint16_t*)bitmap;
 796        for (int col=0;col<arw; col++)
 797        {
 798            *dst++ = *bmp_ptr++;            
 799        } 
 800        bitmap += w;
 801        l++;
 802      } 
 803    }
 804    else {
 805      for (int row=0;row<arh; row++)
 806      {
 807        vga_pixel * dst=&framebuffer[l*fb_stride+arx];  
 808        bmp_ptr = (uint16_t *)bitmap;
 809        for (int col=0;col<arw; col++)
 810        {
 811            uint16_t pix= *bmp_ptr++;
 812            *dst++ = VGA_RGB(R16(pix),G16(pix),B16(pix));
 813        } 
 814        bitmap += w;
 815        l++;
 816      }     
 817    }  
 818  
 819  }
 820  
 821  void PICO_DSP::drawSprite(int16_t x, int16_t y, const dsp_pixel *bitmap) {
 822      drawSprite(x,y,bitmap, 0,0,0,0);
 823  }
 824  
 825  void PICO_DSP::writeLine(int width, int height, int y, dsp_pixel *buf) {
 826    if (gfxmode == MODE_TFT_320x240) {
 827      uint16_t * block=blocks[y>>6];
 828      uint16_t * dst=&block[(y&0x3F)*fb_stride];
 829      if (width > fb_width) {
 830  #ifdef TFT_LINEARINT   
 831        int delta = (width/(width-fb_width))-1;   
 832        int pos = delta;
 833        for (int i=0; i<fb_width; i++)
 834        {
 835          uint16_t val = *buf++;
 836          pos--;      
 837          if (pos == 0) {
 838  #ifdef LINEARINT_HACK        
 839            val  = ((uint32_t)*buf++ + val)/2;
 840  #else
 841            uint16_t val2 = *buf++;
 842            val = RGBVAL16((R16(val)+R16(val2))/2,(G16(val)+G16(val2))/2,(B16(val)+B16(val2))/2);
 843   #endif        
 844            pos = delta;
 845          }
 846          *dst++=val;
 847        }
 848    #else
 849        int step = ((width << 8)/fb_width);
 850        int pos = 0;
 851        for (int i=0; i<fb_width; i++)
 852        {
 853          *dst++=buf[pos >> 8];
 854          pos +=step;
 855        }  
 856    #endif       
 857      }
 858      else if ((width*2) == fb_width) 
 859      {
 860        for (int i=0; i<width; i++)
 861        {
 862          *dst++=*buf;
 863          *dst++=*buf++;
 864        }       
 865      }
 866      else
 867      {
 868        if (width <= fb_width) {
 869          dst += (fb_width-width)/2;
 870        }
 871        for (int i=0; i<width; i++)
 872        {
 873          *dst++=*buf++;
 874        }       
 875      }    
 876    }
 877    else {
 878      if ( (height<fb_height) && (height > 2) ) y += (fb_height-height)/2;
 879      vga_pixel * dst=&framebuffer[y*fb_stride];    
 880      if (width > fb_width) {
 881        int step = ((width << 8)/fb_width);
 882        int pos = 0;
 883        for (int i=0; i<fb_width; i++)
 884        {
 885          uint16_t pix = buf[pos >> 8];
 886          *dst++ = VGA_RGB(R16(pix),G16(pix),B16(pix)); 
 887          pos +=step;
 888        }        
 889      }
 890      else if ((width*2) == fb_width) {
 891        for (int i=0; i<width; i++)
 892        {
 893          uint16_t pix = *buf++;
 894          vga_pixel col = VGA_RGB(R16(pix),G16(pix),B16(pix));
 895          *dst++= col;
 896          *dst++= col;
 897        }       
 898      }
 899      else {
 900        if (width <= fb_width) {
 901          dst += (fb_width-width)/2;
 902        }
 903        for (int i=0; i<width; i++)
 904        {
 905          uint16_t pix = *buf++;
 906          *dst++= VGA_RGB(R16(pix),G16(pix),B16(pix));
 907        }      
 908      }
 909    }  
 910  }
 911  
 912  void PICO_DSP::writeLinePal(int width, int height, int y, uint8_t *buf, dsp_pixel *palette) {
 913    if (gfxmode == MODE_TFT_320x240) {
 914      if ( (height<fb_height) && (height > 2) ) y += (fb_height-height)/2;
 915      uint16_t * block=blocks[y>>6];
 916      uint16_t * dst=&block[(y&0x3F)*fb_stride];
 917      if (width > fb_width) {
 918  #ifdef TFT_LINEARINT    
 919        int delta = (width/(width-fb_width))-1;
 920        int pos = delta;
 921        for (int i=0; i<fb_width; i++)
 922        {
 923          uint16_t val = palette[*buf++];
 924          pos--;
 925          if (pos == 0) {
 926  #ifdef LINEARINT_HACK
 927            val  = ((uint32_t)palette[*buf++] + val)/2;
 928  #else
 929            uint16_t val2 = *buf++;
 930            val = RGBVAL16((R16(val)+R16(val2))/2,(G16(val)+G16(val2))/2,(B16(val)+B16(val2))/2);
 931  #endif        
 932            pos = delta;
 933          }
 934          *dst++=val;
 935        }
 936  #else
 937        int step = ((width << 8)/fb_width);
 938        int pos = 0;
 939        for (int i=0; i<fb_width; i++)
 940        {
 941          *dst++=palette[buf[pos >> 8]];
 942          pos +=step;
 943        }  
 944  #endif
 945      }
 946      else if ((width*2) == fb_width) {
 947        for (int i=0; i<width; i++)
 948        {
 949          *dst++=palette[*buf];
 950          *dst++=palette[*buf++];
 951        } 
 952      }
 953      else {
 954        if (width <= fb_width) {
 955          dst += (fb_width-width)/2;
 956        }
 957        for (int i=0; i<width; i++)
 958        {
 959          *dst++=palette[*buf++];
 960        } 
 961      }    
 962    }  
 963    else {
 964      if ( (height<fb_height) && (height > 2) ) y += (fb_height-height)/2;
 965      vga_pixel * dst=&framebuffer[y*fb_stride];
 966      if (width > fb_width) {
 967        int step = ((width << 8)/fb_width);
 968        int pos = 0;
 969        for (int i=0; i<fb_width; i++)
 970        {
 971          uint16_t pix = palette[buf[pos >> 8]];
 972          *dst++= VGA_RGB(R16(pix),G16(pix),B16(pix));
 973          pos +=step;
 974        }  
 975      }
 976      else if ((width*2) == fb_width) {
 977        for (int i=0; i<width; i++)
 978        {
 979          uint16_t pix = palette[*buf++];
 980          *dst++= VGA_RGB(R16(pix),G16(pix),B16(pix));
 981          *dst++= VGA_RGB(R16(pix),G16(pix),B16(pix));
 982        } 
 983      }
 984      else {
 985        if (width <= fb_width) {
 986          dst += (fb_width-width)/2;
 987        }
 988        for (int i=0; i<width; i++)
 989        {
 990          uint16_t pix = palette[*buf++];
 991          *dst++= VGA_RGB(R16(pix),G16(pix),B16(pix));
 992        } 
 993      }
 994    }
 995  }
 996  
 997  void PICO_DSP::writeScreenPal(int width, int height, int stride, uint8_t *buf, dsp_pixel *palette16) {
 998    uint8_t *src; 
 999    int i,j,y=0;
1000    int sy = 0;  
1001    int systep=(1<<8);
1002    int h = height;
1003    if (height <= ( (2*fb_height)/3)) {
1004      systep=(systep*height)/fb_height;
1005      h = fb_height;
1006    }  
1007    if (gfxmode == MODE_TFT_320x240) {
1008      if (width*2 <= fb_width) {
1009        for (j=0; j<h; j++)
1010        {
1011          uint16_t * block=blocks[y>>6];
1012          uint16_t * dst=&block[(y&0x3F)*fb_stride];        
1013          src=&buf[(sy>>8)*stride];
1014          for (i=0; i<width; i++)
1015          {
1016            uint16_t val = palette16[*src++];
1017            *dst++ = val;
1018            *dst++ = val;
1019          }
1020          y++;
1021          sy+=systep;  
1022        }
1023      }
1024      else if (width <= fb_width) {
1025        for (j=0; j<h; j++)
1026        {
1027          uint16_t * block=blocks[y>>6];
1028          uint16_t * dst=&block[(y&0x3F)*fb_stride+(fb_width-width)/2];        
1029          src=&buf[(sy>>8)*stride];
1030          for (i=0; i<width; i++)
1031          {
1032            uint16_t val = palette16[*src++];
1033            *dst++ = val;
1034          }
1035          y++;
1036          sy+=systep;  
1037        }
1038      }
1039    }       
1040    else { // VGA
1041      if (width*2 <= fb_width) {
1042        for (j=0; j<h; j++)
1043        {
1044          vga_pixel * dst=&framebuffer[y*fb_stride];                
1045          src=&buf[(sy>>8)*stride];
1046          for (i=0; i<width; i++)
1047          {
1048            uint16_t pix = palette16[*src++];
1049            *dst++ = VGA_RGB(R16(pix),G16(pix),B16(pix));
1050            *dst++ = VGA_RGB(R16(pix),G16(pix),B16(pix));
1051          }
1052          y++;
1053          sy+=systep;  
1054        }
1055      }
1056      else if (width <= fb_width) {
1057        for (j=0; j<h; j++)
1058        {
1059          vga_pixel * dst=&framebuffer[y*fb_stride+(fb_width-width)/2];                
1060          src=&buf[(sy>>8)*stride];
1061          for (i=0; i<width; i++)
1062          {
1063            uint16_t pix = palette16[*src++];
1064            *dst++ = VGA_RGB(R16(pix),G16(pix),B16(pix));
1065          }
1066          y++;
1067          sy+=systep;  
1068        }
1069      }
1070    }
1071  }
1072  
1073  
1074  /***********************************************************************************************
1075      No DMA functions
1076   ***********************************************************************************************/
1077  void PICO_DSP::fillScreenNoDma(dsp_pixel color) {
1078    if (gfxmode == MODE_TFT_320x240) {
1079      digitalWrite(_cs, 0);
1080      setArea(0, 0, TFT_REALWIDTH-1, TFT_REALHEIGHT-1);  
1081      int i,j;
1082      for (j=0; j<TFT_REALHEIGHT; j++)
1083      {
1084        for (i=0; i<TFT_REALWIDTH; i++) {
1085          //digitalWrite(_dc, 1);
1086          SPItransfer16(color);     
1087        }
1088      }
1089  #ifdef ILI9341  
1090      digitalWrite(_dc, 0);
1091      SPItransfer(ILI9341_SLPOUT);
1092      digitalWrite(_dc, 1);
1093  #endif
1094      digitalWrite(_cs, 1);
1095      setArea(0, 0, (TFT_REALWIDTH-1), (TFT_REALHEIGHT-1));     
1096    }
1097    else {
1098      fillScreen(color);
1099    }   
1100  }
1101  
1102  void PICO_DSP::drawRectNoDma(int16_t x, int16_t y, int16_t w, int16_t h, dsp_pixel color) {
1103    if (gfxmode == MODE_TFT_320x240) {
1104      digitalWrite(_cs, 0);
1105      setArea(x,y,x+w-1,y+h-1);
1106      int i;
1107      for (i=0; i<(w*h); i++)
1108      {
1109        SPItransfer16(color);
1110      }
1111  #ifdef ILI9341  
1112      digitalWrite(_dc, 0);
1113      SPItransfer(ILI9341_SLPOUT);
1114      digitalWrite(_dc, 1);
1115  #endif
1116      digitalWrite(_cs, 1);
1117      setArea(0, 0, (TFT_REALWIDTH-1), (TFT_REALHEIGHT-1));   
1118    }
1119    else {
1120      drawRect(x, y, w, h, color);
1121    }  
1122  }
1123  
1124  
1125  void PICO_DSP::drawSpriteNoDma(int16_t x, int16_t y, const dsp_pixel *bitmap) {  
1126    drawSpriteNoDma(x,y,bitmap, 0,0,0,0);
1127  }
1128  
1129  void PICO_DSP::drawSpriteNoDma(int16_t x, int16_t y, const dsp_pixel *bitmap, uint16_t arx, uint16_t ary, uint16_t arw, uint16_t arh)
1130  {
1131    if (gfxmode == MODE_TFT_320x240) {
1132      int bmp_offx = 0;
1133      int bmp_offy = 0;
1134      uint16_t *bmp_ptr;
1135      int w =*bitmap++;
1136      int h =*bitmap++;
1137      if ( (arw == 0) || (arh == 0) ) {
1138        // no crop window
1139        arx = x;
1140        ary = y;
1141        arw = w;
1142        arh = h;
1143      }
1144      else {
1145        if ( (x>(arx+arw)) || ((x+w)<arx) || (y>(ary+arh)) || ((y+h)<ary)   ) {
1146          return;
1147        }
1148        // crop area
1149        if ( (x > arx) && (x<(arx+arw)) ) { 
1150          arw = arw - (x-arx);
1151          arx = arx + (x-arx);
1152        } else {
1153          bmp_offx = arx;
1154        }
1155        if ( ((x+w) > arx) && ((x+w)<(arx+arw)) ) {
1156          arw -= (arx+arw-x-w);
1157        }  
1158        if ( (y > ary) && (y<(ary+arh)) ) {
1159          arh = arh - (y-ary);
1160          ary = ary + (y-ary);
1161        } else {
1162          bmp_offy = ary;
1163        }
1164        if ( ((y+h) > ary) && ((y+h)<(ary+arh)) ) {
1165          arh -= (ary+arh-y-h);
1166        }     
1167      }
1168      digitalWrite(_cs, 0);
1169      setArea(arx, ary, arx+arw-1, ary+arh-1);        
1170      bitmap = bitmap + bmp_offy*w + bmp_offx;
1171      for (int row=0;row<arh; row++)
1172      {
1173        bmp_ptr = (uint16_t*)bitmap;
1174        for (int col=0;col<arw; col++)
1175        {
1176            SPItransfer16(*bmp_ptr++);             
1177        } 
1178        bitmap +=  w;
1179      }
1180  #ifdef ILI9341  
1181      digitalWrite(_dc, 0);
1182      SPItransfer(ILI9341_SLPOUT);
1183      digitalWrite(_dc, 1);
1184  #endif
1185      setArea(0, 0, TFT_REALWIDTH-1, TFT_REALHEIGHT-1);  
1186      digitalWrite(_cs, 1);  
1187    }
1188    else {
1189      drawSprite(x, y, bitmap, arx, ary, arw, arh);
1190    }   
1191  }
1192  
1193  void PICO_DSP::drawTextNoDma(int16_t x, int16_t y, const char * text, dsp_pixel fgcolor, dsp_pixel bgcolor, bool doublesize) {
1194    if (gfxmode == MODE_TFT_320x240) {
1195      uint16_t c;
1196      while ((c = *text++)) {
1197        const unsigned char * charpt=&font8x8[c][0];
1198        digitalWrite(_cs, 0);
1199        setArea(x,y,x+7,y+(doublesize?15:7));
1200        for (int i=0;i<8;i++)
1201        {
1202          unsigned char bits;
1203          if (doublesize) {
1204            bits = *charpt;     
1205            if (bits&0x01) SPItransfer16(fgcolor);
1206            else SPItransfer16(bgcolor);
1207            bits = bits >> 1;     
1208            if (bits&0x01) SPItransfer16(fgcolor);
1209            else SPItransfer16(bgcolor);
1210            bits = bits >> 1;     
1211            if (bits&0x01) SPItransfer16(fgcolor);
1212            else SPItransfer16(bgcolor);
1213            bits = bits >> 1;     
1214            if (bits&0x01) SPItransfer16(fgcolor);
1215            else SPItransfer16(bgcolor);
1216            bits = bits >> 1;     
1217            if (bits&0x01) SPItransfer16(fgcolor);
1218            else SPItransfer16(bgcolor);
1219            bits = bits >> 1;     
1220            if (bits&0x01) SPItransfer16(fgcolor);
1221            else SPItransfer16(bgcolor);
1222            bits = bits >> 1;     
1223            if (bits&0x01) SPItransfer16(fgcolor);
1224            else SPItransfer16(bgcolor);
1225            bits = bits >> 1;     
1226            if (bits&0x01) SPItransfer16(fgcolor);
1227            else SPItransfer16(bgcolor);       
1228          }
1229          bits = *charpt++;     
1230          if (bits&0x01) SPItransfer16(fgcolor);
1231          else SPItransfer16(bgcolor);
1232          bits = bits >> 1;     
1233          if (bits&0x01) SPItransfer16(fgcolor);
1234          else SPItransfer16(bgcolor);
1235          bits = bits >> 1;     
1236          if (bits&0x01) SPItransfer16(fgcolor);
1237          else SPItransfer16(bgcolor);
1238          bits = bits >> 1;     
1239          if (bits&0x01) SPItransfer16(fgcolor);
1240          else SPItransfer16(bgcolor);
1241          bits = bits >> 1;     
1242          if (bits&0x01) SPItransfer16(fgcolor);
1243          else SPItransfer16(bgcolor);
1244          bits = bits >> 1;     
1245          if (bits&0x01) SPItransfer16(fgcolor);
1246          else SPItransfer16(bgcolor);
1247          bits = bits >> 1;     
1248          if (bits&0x01) SPItransfer16(fgcolor);
1249          else SPItransfer16(bgcolor);
1250          bits = bits >> 1;     
1251          if (bits&0x01) SPItransfer16(fgcolor);
1252          else SPItransfer16(bgcolor);
1253        }
1254        x +=8;
1255  #ifdef ILI9341  
1256        digitalWrite(_dc, 0);
1257        SPItransfer(ILI9341_SLPOUT);
1258        digitalWrite(_dc, 1);
1259  #endif
1260        digitalWrite(_cs, 1); 
1261      }
1262  
1263      digitalWrite(_cs, 0);
1264      setArea(0, 0, (TFT_REALWIDTH-1), (TFT_REALHEIGHT-1));  
1265      digitalWrite(_cs, 1);
1266    }
1267    else {
1268      drawText(x, y, text, fgcolor, bgcolor, doublesize);
1269    } 
1270  }
1271  
1272  /*******************************************************************
1273   Experimental PWM interrupt based sound driver !!!
1274  *******************************************************************/
1275  #include "hardware/irq.h"
1276  #include "hardware/pwm.h"
1277  
1278  static bool fillfirsthalf = true;
1279  static uint16_t cnt = 0;
1280  static uint16_t sampleBufferSize = 0;
1281  
1282  static void (*fillsamples)(short * stream, int len) = nullptr;
1283  
1284  static uint32_t * i2s_tx_buffer;
1285  static short * i2s_tx_buffer16;
1286  
1287  static void SOFTWARE_isr() {
1288    if (fillfirsthalf) {
1289      fillsamples((short *)i2s_tx_buffer, sampleBufferSize);
1290    }  
1291    else { 
1292      fillsamples((short *)&i2s_tx_buffer[sampleBufferSize/2], sampleBufferSize);
1293    }
1294  }
1295  
1296  static void AUDIO_isr() {
1297    pwm_clear_irq(pwm_gpio_to_slice_num(AUDIO_PIN));
1298    long s = i2s_tx_buffer16[cnt++]; 
1299    s += i2s_tx_buffer16[cnt++];
1300    s = s/2 + 32767; 
1301    pwm_set_gpio_level(AUDIO_PIN, s >> 8);
1302    cnt = cnt & (sampleBufferSize*2-1);
1303  
1304    if (cnt == 0) {
1305      fillfirsthalf = false;
1306      //irq_set_pending(RTC_IRQ+1);
1307      multicore_fifo_push_blocking(0);
1308    } 
1309    else if (cnt == sampleBufferSize) {
1310      fillfirsthalf = true;
1311      //irq_set_pending(RTC_IRQ+1);
1312      multicore_fifo_push_blocking(0);
1313    }
1314  }
1315  
1316  static void core1_sio_irq() {
1317    irq_clear(SIO_IRQ_PROC1);
1318    while(multicore_fifo_rvalid()) {
1319      uint16_t raw = multicore_fifo_pop_blocking();
1320      SOFTWARE_isr();
1321    } 
1322    multicore_fifo_clear_irq();
1323  }
1324  
1325  static void core1_func_tft() {
1326      multicore_fifo_clear_irq();
1327      irq_set_exclusive_handler(SIO_IRQ_PROC1,core1_sio_irq);
1328      //irq_set_priority (SIO_IRQ_PROC1, 129);    
1329      irq_set_enabled(SIO_IRQ_PROC1,true);
1330  
1331      while (true) {
1332          tight_loop_contents();
1333      }
1334  }
1335  
1336  void PICO_DSP::begin_audio(int samplesize, void (*callback)(short * stream, int len))
1337  {
1338    fillsamples = callback;
1339    i2s_tx_buffer =  (uint32_t*)malloc(samplesize*sizeof(uint32_t));
1340  
1341    if (i2s_tx_buffer == NULL) {
1342      printf("sound buffer could not be allocated!!!!!\n");
1343      return;  
1344    }
1345    memset((void*)i2s_tx_buffer,0, samplesize*sizeof(uint32_t));
1346    printf("sound buffer allocated\n");
1347  
1348    i2s_tx_buffer16 = (short*)i2s_tx_buffer;
1349  
1350    sampleBufferSize = samplesize;
1351  
1352    gpio_set_function(AUDIO_PIN, GPIO_FUNC_PWM);
1353  
1354    if (gfxmode == MODE_TFT_320x240) {
1355      multicore_launch_core1(core1_func_tft);
1356    }
1357    
1358    int audio_pin_slice = pwm_gpio_to_slice_num(AUDIO_PIN);
1359    // Setup PWM interrupt to fire when PWM cycle is complete
1360    pwm_clear_irq(audio_pin_slice);
1361    pwm_set_irq_enabled(audio_pin_slice, true);
1362    irq_set_exclusive_handler(PWM_IRQ_WRAP, AUDIO_isr);
1363    irq_set_priority (PWM_IRQ_WRAP, 128);
1364    irq_set_enabled(PWM_IRQ_WRAP, true);
1365  
1366    //irq_set_exclusive_handler(RTC_IRQ+1,SOFTWARE_isr);
1367    //irq_set_priority (RTC_IRQ+1, 120);
1368    //irq_set_enabled(RTC_IRQ+1,true);
1369  
1370  
1371    // Setup PWM for audio output
1372    pwm_config config = pwm_get_default_config();
1373  //  pwm_config_set_clkdiv(&config, 5.5f);
1374    pwm_config_set_clkdiv(&config, 50.0f);
1375    pwm_config_set_wrap(&config, 254);
1376    pwm_init(audio_pin_slice, &config, true);
1377  
1378    pwm_set_gpio_level(AUDIO_PIN, 0);
1379    printf("sound initialized\n");
1380  }
1381   
1382  void PICO_DSP::end_audio()
1383  {
1384    if (i2s_tx_buffer != NULL) {
1385      free(i2s_tx_buffer);
1386    }  
1387  }
1388  
1389  
1390   
1391