|
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206 |
- /***************************************************
- This is a library for the Adafruit 1.8" SPI display.
- This library works with the Adafruit 1.8" TFT Breakout w/SD card
- ----> http://www.adafruit.com/products/358
- as well as Adafruit raw 1.8" TFT display
- ----> http://www.adafruit.com/products/618
-
- Check out the links above for our tutorials and wiring diagrams
- These displays use SPI to communicate, 4 or 5 pins are required to
- interface (RST is optional)
- Adafruit invests time and resources providing this open source code,
- please support Adafruit and open-source hardware by purchasing
- products from Adafruit!
-
- Written by Limor Fried/Ladyada for Adafruit Industries.
- MIT license, all text above must be included in any redistribution
- ****************************************************/
-
- #include "ST7735_t3.h"
- #include "ST7789_t3.h"
- #include <limits.h>
- #include "pins_arduino.h"
- #include "wiring_private.h"
- #include <SPI.h>
-
- #ifdef ENABLE_ST77XX_FRAMEBUFFER
- //#define DEBUG_ASYNC_UPDATE
- //#define DEBUG_ASYNC_LEDS
- #ifdef DEBUG_ASYNC_LEDS
- #define DEBUG_PIN_1 0
- #define DEBUG_PIN_2 1
- #define DEBUG_PIN_3 2
- #endif
-
- volatile short _dma_dummy_rx;
-
- ST7735_t3 *ST7735_t3::_dmaActiveDisplay[3] = {0, 0, 0};
-
- #if defined(__MK66FX1M0__)
- DMASetting ST7735_t3::_dmasettings[3][4];
- #endif
-
- #if defined(__IMXRT1062__) // Teensy 4.x
- // On T4 Setup the buffers to be used one per SPI buss...
- // This way we make sure it is hopefully in uncached memory
- ST7735DMA_Data ST7735_t3::_dma_data[3]; // one structure for each SPI buss...
- #endif
-
- #endif
-
- // Constructor when using software SPI. All output pins are configurable.
- ST7735_t3::ST7735_t3(uint8_t cs, uint8_t rs, uint8_t sid, uint8_t sclk, uint8_t rst)
- {
- _cs = cs;
- _rs = rs;
- _sid = sid;
- _sclk = sclk;
- _rst = rst;
- _rot = 0xff;
- hwSPI = false;
- #ifdef ENABLE_ST77XX_FRAMEBUFFER
- _pfbtft = NULL;
- _use_fbtft = 0; // Are we in frame buffer mode?
- _we_allocated_buffer = NULL;
- _dma_state = 0;
- #endif
- _screenHeight = ST7735_TFTHEIGHT_160;
- _screenWidth = ST7735_TFTWIDTH;
-
- _width = _screenWidth;
- _height = _screenHeight;
-
- cursor_y = cursor_x = 0;
- textsize_x = 1;
- textsize_y = 1;
- textcolor = textbgcolor = 0xFFFF;
- wrap = true;
- font = NULL;
- gfxFont = NULL;
- setClipRect();
- setOrigin();
- }
-
-
- // Constructor when using hardware SPI. Faster, but must use SPI pins
- // specific to each board type (e.g. 11,13 for Uno, 51,52 for Mega, etc.)
- ST7735_t3::ST7735_t3(uint8_t cs, uint8_t rs, uint8_t rst)
- {
- _cs = cs;
- _rs = rs;
- _rst = rst;
- _rot = 0xff;
- hwSPI = true;
- _sid = _sclk = (uint8_t)-1;
- #ifdef ENABLE_ST77XX_FRAMEBUFFER
- _pfbtft = NULL;
- _use_fbtft = 0; // Are we in frame buffer mode?
- _we_allocated_buffer = NULL;
- _dma_state = 0;
- #endif
- _screenHeight = ST7735_TFTHEIGHT_160;
- _screenWidth = ST7735_TFTWIDTH;
-
- cursor_y = cursor_x = 0;
- textsize_x = 1;
- textsize_y = 1;
- textcolor = textbgcolor = 0xFFFF;
- wrap = true;
- font = NULL;
- gfxFont = NULL;
- setClipRect();
- setOrigin();
- }
-
-
-
- /***************************************************************/
- /* Teensy 3.0, 3.1, 3.2, 3.5, 3.6 */
- /***************************************************************/
- #if defined(__MK20DX128__) || defined(__MK20DX256__) || defined(__MK64FX512__) || defined(__MK66FX1M0__)
-
- inline void ST7735_t3::waitTransmitComplete(void) {
- uint32_t tmp __attribute__((unused));
- while (!(_pkinetisk_spi->SR & SPI_SR_TCF)) ; // wait until final output done
- tmp = _pkinetisk_spi->POPR; // drain the final RX FIFO word
- }
-
- inline void ST7735_t3::waitTransmitComplete(uint32_t mcr) {
- uint32_t tmp __attribute__((unused));
- while (1) {
- uint32_t sr = _pkinetisk_spi->SR;
- if (sr & SPI_SR_EOQF) break; // wait for last transmit
- if (sr & 0xF0) tmp = _pkinetisk_spi->POPR;
- }
- _pkinetisk_spi->SR = SPI_SR_EOQF;
- _pkinetisk_spi->MCR = mcr;
- while (_pkinetisk_spi->SR & 0xF0) {
- tmp = _pkinetisk_spi->POPR;
- }
- }
-
- inline void ST7735_t3::spiwrite(uint8_t c)
- {
- // pass 1 if we actually are setup to with MOSI and SCLK on hardware SPI use it...
- if (_pspi) {
- _pspi->transfer(c);
- return;
- }
-
- for (uint8_t bit = 0x80; bit; bit >>= 1) {
- *datapin = ((c & bit) ? 1 : 0);
- *clkpin = 1;
- *clkpin = 0;
- }
- }
-
- inline void ST7735_t3::spiwrite16(uint16_t d)
- {
- // pass 1 if we actually are setup to with MOSI and SCLK on hardware SPI use it...
- if (_pspi) {
- _pspi->transfer16(d);
- return;
- }
- spiwrite(d >> 8);
- spiwrite(d);
- }
-
- void ST7735_t3::writecommand(uint8_t c)
- {
- if (hwSPI) {
- _pkinetisk_spi->PUSHR = c | (pcs_command << 16) | SPI_PUSHR_CTAS(0);
- while (((_pkinetisk_spi->SR) & (15 << 12)) > _fifo_full_test) ; // wait if FIFO full
- } else {
- *rspin = 0;
- spiwrite(c);
- }
- }
-
- void ST7735_t3::writecommand_last(uint8_t c) {
- if (hwSPI) {
- uint32_t mcr = _pkinetisk_spi->MCR;
- _pkinetisk_spi->PUSHR = c | (pcs_command << 16) | SPI_PUSHR_CTAS(0) | SPI_PUSHR_EOQ;
- waitTransmitComplete(mcr);
- } else {
- *rspin = 0;
- spiwrite(c);
- }
- }
-
- void ST7735_t3::writedata(uint8_t c)
- {
- if (hwSPI) {
- _pkinetisk_spi->PUSHR = c | (pcs_data << 16) | SPI_PUSHR_CTAS(0);
- while (((_pkinetisk_spi->SR) & (15 << 12)) > _fifo_full_test) ; // wait if FIFO full
- } else {
- *rspin = 1;
- spiwrite(c);
- }
- }
-
- void ST7735_t3::writedata_last(uint8_t c)
- {
- if (hwSPI) {
- uint32_t mcr = _pkinetisk_spi->MCR;
- _pkinetisk_spi->PUSHR = c | (pcs_data << 16) | SPI_PUSHR_CTAS(0) | SPI_PUSHR_EOQ;
- waitTransmitComplete(mcr);
- } else {
- *rspin = 1;
- spiwrite(c);
- }
- }
-
- void ST7735_t3::writedata16(uint16_t d)
- {
- if (hwSPI) {
- _pkinetisk_spi->PUSHR = d | (pcs_data << 16) | SPI_PUSHR_CTAS(1);
- while (((_pkinetisk_spi->SR) & (15 << 12)) > _fifo_full_test) ; // wait if FIFO full
- } else {
- *rspin = 1;
- spiwrite16(d);
- }
- }
-
-
- void ST7735_t3::writedata16_last(uint16_t d)
- {
- if (hwSPI) {
- uint32_t mcr = _pkinetisk_spi->MCR;
- _pkinetisk_spi->PUSHR = d | (pcs_data << 16) | SPI_PUSHR_CTAS(1) | SPI_PUSHR_EOQ;
- waitTransmitComplete(mcr);
- } else {
- *rspin = 1;
- spiwrite16(d);
- }
- }
-
-
- #define CTAR_24MHz (SPI_CTAR_PBR(0) | SPI_CTAR_BR(0) | SPI_CTAR_CSSCK(0) | SPI_CTAR_DBR)
- #define CTAR_16MHz (SPI_CTAR_PBR(1) | SPI_CTAR_BR(0) | SPI_CTAR_CSSCK(0) | SPI_CTAR_DBR)
- #define CTAR_12MHz (SPI_CTAR_PBR(0) | SPI_CTAR_BR(0) | SPI_CTAR_CSSCK(0))
- #define CTAR_8MHz (SPI_CTAR_PBR(1) | SPI_CTAR_BR(0) | SPI_CTAR_CSSCK(0))
- #define CTAR_6MHz (SPI_CTAR_PBR(0) | SPI_CTAR_BR(1) | SPI_CTAR_CSSCK(1))
- #define CTAR_4MHz (SPI_CTAR_PBR(1) | SPI_CTAR_BR(1) | SPI_CTAR_CSSCK(1))
-
- void ST7735_t3::setBitrate(uint32_t n)
- {
- if (n >= 24000000) {
- ctar = CTAR_24MHz;
- } else if (n >= 16000000) {
- ctar = CTAR_16MHz;
- } else if (n >= 12000000) {
- ctar = CTAR_12MHz;
- } else if (n >= 8000000) {
- ctar = CTAR_8MHz;
- } else if (n >= 6000000) {
- ctar = CTAR_6MHz;
- } else {
- ctar = CTAR_4MHz;
- }
- SIM_SCGC6 |= SIM_SCGC6_SPI0;
- _pkinetisk_spi->MCR = SPI_MCR_MDIS | SPI_MCR_HALT;
- _pkinetisk_spi->CTAR0 = ctar | SPI_CTAR_FMSZ(7);
- _pkinetisk_spi->CTAR1 = ctar | SPI_CTAR_FMSZ(15);
- _pkinetisk_spi->MCR = SPI_MCR_MSTR | SPI_MCR_PCSIS(0x1F) | SPI_MCR_CLR_TXF | SPI_MCR_CLR_RXF;
- }
-
-
- /***************************************************************/
- /* Teensy 4. */
- /***************************************************************/
- #elif defined(__IMXRT1062__) // Teensy 4.x
- inline void ST7735_t3::spiwrite(uint8_t c)
- {
- //Serial.println(c, HEX);
- if (_pspi) {
- _pspi->transfer(c);
- } else {
- // Fast SPI bitbang swiped from LPD8806 library
- for(uint8_t bit = 0x80; bit; bit >>= 1) {
- if(c & bit) DIRECT_WRITE_HIGH(_mosiport, _mosipinmask);
- else DIRECT_WRITE_LOW(_mosiport, _mosipinmask);
- DIRECT_WRITE_HIGH(_sckport, _sckpinmask);
- asm("nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop;");
- DIRECT_WRITE_LOW(_sckport, _sckpinmask);
- }
- }
- }
-
- void ST7735_t3::writecommand(uint8_t c)
- {
- if (hwSPI) {
- maybeUpdateTCR(_tcr_dc_assert | LPSPI_TCR_FRAMESZ(7) /*| LPSPI_TCR_CONT*/);
- _pimxrt_spi->TDR = c;
- _pending_rx_count++; //
- waitFifoNotFull();
- } else {
- DIRECT_WRITE_LOW(_dcport, _dcpinmask);
- spiwrite(c);
- }
- }
-
- void ST7735_t3::writecommand_last(uint8_t c)
- {
- if (hwSPI) {
- maybeUpdateTCR(_tcr_dc_assert | LPSPI_TCR_FRAMESZ(7));
- _pimxrt_spi->TDR = c;
- _pending_rx_count++; //
- waitTransmitComplete();
- } else {
- DIRECT_WRITE_LOW(_dcport, _dcpinmask);
- spiwrite(c);
- }
-
- }
-
- void ST7735_t3::writedata(uint8_t c)
- {
- if (hwSPI) {
- maybeUpdateTCR(_tcr_dc_not_assert | LPSPI_TCR_FRAMESZ(7));
- _pimxrt_spi->TDR = c;
- _pending_rx_count++; //
- waitTransmitComplete();
- } else {
- DIRECT_WRITE_HIGH(_dcport, _dcpinmask);
- spiwrite(c);
- }
- }
-
- void ST7735_t3::writedata_last(uint8_t c)
- {
- if (hwSPI) {
- maybeUpdateTCR(_tcr_dc_not_assert | LPSPI_TCR_FRAMESZ(7));
- _pimxrt_spi->TDR = c;
- _pending_rx_count++; //
- waitTransmitComplete();
- } else {
- DIRECT_WRITE_HIGH(_dcport, _dcpinmask);
- spiwrite(c);
- }
- }
-
-
- void ST7735_t3::writedata16(uint16_t d)
- {
- if (hwSPI) {
- maybeUpdateTCR(_tcr_dc_not_assert | LPSPI_TCR_FRAMESZ(15) | LPSPI_TCR_CONT);
- _pimxrt_spi->TDR = d;
- _pending_rx_count++; //
- waitFifoNotFull();
- } else {
- DIRECT_WRITE_HIGH(_dcport, _dcpinmask);
- spiwrite(d >> 8);
- spiwrite(d);
- }
- }
-
- void ST7735_t3::writedata16_last(uint16_t d)
- {
- if (hwSPI) {
- maybeUpdateTCR(_tcr_dc_not_assert | LPSPI_TCR_FRAMESZ(15));
- _pimxrt_spi->TDR = d;
- // _pimxrt_spi->SR = LPSPI_SR_WCF | LPSPI_SR_FCF | LPSPI_SR_TCF;
- _pending_rx_count++; //
- waitTransmitComplete();
- } else {
- DIRECT_WRITE_HIGH(_dcport, _dcpinmask);
- spiwrite(d >> 8);
- spiwrite(d);
- }
- }
-
- void ST7735_t3::setBitrate(uint32_t n)
- {
- if (n >= 8000000) {
- SPI.setClockDivider(SPI_CLOCK_DIV2);
- } else if (n >= 4000000) {
- SPI.setClockDivider(SPI_CLOCK_DIV4);
- } else if (n >= 2000000) {
- SPI.setClockDivider(SPI_CLOCK_DIV8);
- } else {
- SPI.setClockDivider(SPI_CLOCK_DIV16);
- }
- }
-
-
- /***************************************************************/
- /* Teensy LC */
- /***************************************************************/
- #elif defined(__MKL26Z64__)
-
-
- inline void ST7735_t3::spiwrite(uint8_t c)
- {
- //Serial.println(c, HEX);
- if (hwSPI) {
- SPI.transfer(c);
- } else if (hwSPI1) {
- SPI1.transfer(c);
- } else {
- // Fast SPI bitbang swiped from LPD8806 library
- for(uint8_t bit = 0x80; bit; bit >>= 1) {
- if(c & bit) *dataport |= datapinmask;
- else *dataport &= ~datapinmask;
- *clkport |= clkpinmask;
- *clkport &= ~clkpinmask;
- }
- }
- }
-
- void ST7735_t3::writecommand(uint8_t c)
- {
- *rsport &= ~rspinmask;
- spiwrite(c);
- }
- void ST7735_t3::writecommand_last(uint8_t c)
- {
- *rsport &= ~rspinmask;
- spiwrite(c);
- }
-
- void ST7735_t3::writedata(uint8_t c)
- {
- *rsport |= rspinmask;
- spiwrite(c);
- }
-
- void ST7735_t3::writedata_last(uint8_t c)
- {
- *rsport |= rspinmask;
- spiwrite(c);
- }
-
- void ST7735_t3::writedata16(uint16_t d)
- {
- *rsport |= rspinmask;
- spiwrite(d >> 8);
- spiwrite(d);
- }
-
- void ST7735_t3::writedata16_last(uint16_t d)
- {
- *rsport |= rspinmask;
- spiwrite(d >> 8);
- spiwrite(d);
- }
-
- void ST7735_t3::setBitrate(uint32_t n)
- {
- if (n >= 8000000) {
- SPI.setClockDivider(SPI_CLOCK_DIV2);
- } else if (n >= 4000000) {
- SPI.setClockDivider(SPI_CLOCK_DIV4);
- } else if (n >= 2000000) {
- SPI.setClockDivider(SPI_CLOCK_DIV8);
- } else {
- SPI.setClockDivider(SPI_CLOCK_DIV16);
- }
- }
- #endif //#if defined(__SAM3X8E__)
-
-
- // Rather than a bazillion writecommand() and writedata() calls, screen
- // initialization commands and arguments are organized in these tables
- // stored in PROGMEM. The table may look bulky, but that's mostly the
- // formatting -- storage-wise this is hundreds of bytes more compact
- // than the equivalent code. Companion function follows.
- #define DELAY 0x80
- static const uint8_t PROGMEM
- Bcmd[] = { // Initialization commands for 7735B screens
- 18, // 18 commands in list:
- ST7735_SWRESET, DELAY, // 1: Software reset, no args, w/delay
- 50, // 50 ms delay
- ST7735_SLPOUT , DELAY, // 2: Out of sleep mode, no args, w/delay
- 255, // 255 = 500 ms delay
- ST7735_COLMOD , 1+DELAY, // 3: Set color mode, 1 arg + delay:
- 0x05, // 16-bit color
- 10, // 10 ms delay
- ST7735_FRMCTR1, 3+DELAY, // 4: Frame rate control, 3 args + delay:
- 0x00, // fastest refresh
- 0x06, // 6 lines front porch
- 0x03, // 3 lines back porch
- 10, // 10 ms delay
- ST7735_MADCTL , 1 , // 5: Memory access ctrl (directions), 1 arg:
- 0x08, // Row addr/col addr, bottom to top refresh
- ST7735_DISSET5, 2 , // 6: Display settings #5, 2 args, no delay:
- 0x15, // 1 clk cycle nonoverlap, 2 cycle gate
- // rise, 3 cycle osc equalize
- 0x02, // Fix on VTL
- ST7735_INVCTR , 1 , // 7: Display inversion control, 1 arg:
- 0x0, // Line inversion
- ST7735_PWCTR1 , 2+DELAY, // 8: Power control, 2 args + delay:
- 0x02, // GVDD = 4.7V
- 0x70, // 1.0uA
- 10, // 10 ms delay
- ST7735_PWCTR2 , 1 , // 9: Power control, 1 arg, no delay:
- 0x05, // VGH = 14.7V, VGL = -7.35V
- ST7735_PWCTR3 , 2 , // 10: Power control, 2 args, no delay:
- 0x01, // Opamp current small
- 0x02, // Boost frequency
- ST7735_VMCTR1 , 2+DELAY, // 11: Power control, 2 args + delay:
- 0x3C, // VCOMH = 4V
- 0x38, // VCOML = -1.1V
- 10, // 10 ms delay
- ST7735_PWCTR6 , 2 , // 12: Power control, 2 args, no delay:
- 0x11, 0x15,
- ST7735_GMCTRP1,16 , // 13: Magical unicorn dust, 16 args, no delay:
- 0x09, 0x16, 0x09, 0x20, // (seriously though, not sure what
- 0x21, 0x1B, 0x13, 0x19, // these config values represent)
- 0x17, 0x15, 0x1E, 0x2B,
- 0x04, 0x05, 0x02, 0x0E,
- ST7735_GMCTRN1,16+DELAY, // 14: Sparkles and rainbows, 16 args + delay:
- 0x0B, 0x14, 0x08, 0x1E, // (ditto)
- 0x22, 0x1D, 0x18, 0x1E,
- 0x1B, 0x1A, 0x24, 0x2B,
- 0x06, 0x06, 0x02, 0x0F,
- 10, // 10 ms delay
- ST7735_CASET , 4 , // 15: Column addr set, 4 args, no delay:
- 0x00, 0x02, // XSTART = 2
- 0x00, 0x81, // XEND = 129
- ST7735_RASET , 4 , // 16: Row addr set, 4 args, no delay:
- 0x00, 0x02, // XSTART = 1
- 0x00, 0x81, // XEND = 160
- ST7735_NORON , DELAY, // 17: Normal display on, no args, w/delay
- 10, // 10 ms delay
- ST7735_DISPON , DELAY, // 18: Main screen turn on, no args, w/delay
- 255 }, // 255 = 500 ms delay
-
- Rcmd1[] = { // Init for 7735R, part 1 (red or green tab)
- 15, // 15 commands in list:
- ST7735_SWRESET, DELAY, // 1: Software reset, 0 args, w/delay
- 150, // 150 ms delay
- ST7735_SLPOUT , DELAY, // 2: Out of sleep mode, 0 args, w/delay
- 255, // 500 ms delay
- ST7735_FRMCTR1, 3 , // 3: Frame rate ctrl - normal mode, 3 args:
- 0x01, 0x2C, 0x2D, // Rate = fosc/(1x2+40) * (LINE+2C+2D)
- ST7735_FRMCTR2, 3 , // 4: Frame rate control - idle mode, 3 args:
- 0x01, 0x2C, 0x2D, // Rate = fosc/(1x2+40) * (LINE+2C+2D)
- ST7735_FRMCTR3, 6 , // 5: Frame rate ctrl - partial mode, 6 args:
- 0x01, 0x2C, 0x2D, // Dot inversion mode
- 0x01, 0x2C, 0x2D, // Line inversion mode
- ST7735_INVCTR , 1 , // 6: Display inversion ctrl, 1 arg, no delay:
- 0x07, // No inversion
- ST7735_PWCTR1 , 3 , // 7: Power control, 3 args, no delay:
- 0xA2,
- 0x02, // -4.6V
- 0x84, // AUTO mode
- ST7735_PWCTR2 , 1 , // 8: Power control, 1 arg, no delay:
- 0xC5, // VGH25 = 2.4C VGSEL = -10 VGH = 3 * AVDD
- ST7735_PWCTR3 , 2 , // 9: Power control, 2 args, no delay:
- 0x0A, // Opamp current small
- 0x00, // Boost frequency
- ST7735_PWCTR4 , 2 , // 10: Power control, 2 args, no delay:
- 0x8A, // BCLK/2, Opamp current small & Medium low
- 0x2A,
- ST7735_PWCTR5 , 2 , // 11: Power control, 2 args, no delay:
- 0x8A, 0xEE,
- ST7735_VMCTR1 , 1 , // 12: Power control, 1 arg, no delay:
- 0x0E,
- ST7735_INVOFF , 0 , // 13: Don't invert display, no args, no delay
- ST7735_MADCTL , 1 , // 14: Memory access control (directions), 1 arg:
- 0xC8, // row addr/col addr, bottom to top refresh
- ST7735_COLMOD , 1 , // 15: set color mode, 1 arg, no delay:
- 0x05 }, // 16-bit color
-
- Rcmd2green[] = { // Init for 7735R, part 2 (green tab only)
- 2, // 2 commands in list:
- ST7735_CASET , 4 , // 1: Column addr set, 4 args, no delay:
- 0x00, 0x02, // XSTART = 0
- 0x00, 0x7F+0x02, // XEND = 127
- ST7735_RASET , 4 , // 2: Row addr set, 4 args, no delay:
- 0x00, 0x01, // XSTART = 0
- 0x00, 0x9F+0x01 }, // XEND = 159
- Rcmd2red[] = { // Init for 7735R, part 2 (red tab only)
- 2, // 2 commands in list:
- ST7735_CASET , 4 , // 1: Column addr set, 4 args, no delay:
- 0x00, 0x00, // XSTART = 0
- 0x00, 0x7F, // XEND = 127
- ST7735_RASET , 4 , // 2: Row addr set, 4 args, no delay:
- 0x00, 0x00, // XSTART = 0
- 0x00, 0x9F }, // XEND = 159
-
- Rcmd2green144[] = { // Init for 7735R, part 2 (green 1.44 tab)
- 2, // 2 commands in list:
- ST7735_CASET , 4 , // 1: Column addr set, 4 args, no delay:
- 0x00, 0x00, // XSTART = 0
- 0x00, 0x7F, // XEND = 127
- ST7735_RASET , 4 , // 2: Row addr set, 4 args, no delay:
- 0x00, 0x00, // XSTART = 0
- 0x00, 0x7F }, // XEND = 127
-
- Rcmd2green160x80[] = { // 7735R init, part 2 (mini 160x80)
- 2, // 2 commands in list:
- ST7735_CASET, 4, // 1: Column addr set, 4 args, no delay:
- 0x00, 0x00, // XSTART = 0
- 0x00, 0x4F, // XEND = 79
- ST7735_RASET, 4, // 2: Row addr set, 4 args, no delay:
- 0x00, 0x00, // XSTART = 0
- 0x00, 0x9F}, // XEND = 159
- Rcmd2minist7735s[] = {
- 3, // 2 commands in list:
- ST7735_CASET , 4 , // 1: Column addr set, 4 args, no delay:
- 0x00, 0x00+26, // XSTART = 0
- 0x00, 0x7F+26, // XEND = 127
- ST7735_RASET , 4 , // 2: Row addr set, 4 args, no delay:
- 0x00, 0x00+1, // XSTART = 0
- 0x00, 0x4F+1, // XEND = 79
- ST7735_INVON, 0}, // these displays need colors inversed
-
- Rcmd3[] = { // Init for 7735R, part 3 (red or green tab)
- 4, // 4 commands in list:
- ST7735_GMCTRP1, 16 , // 1: Magical unicorn dust, 16 args, no delay:
- 0x02, 0x1c, 0x07, 0x12,
- 0x37, 0x32, 0x29, 0x2d,
- 0x29, 0x25, 0x2B, 0x39,
- 0x00, 0x01, 0x03, 0x10,
- ST7735_GMCTRN1, 16 , // 2: Sparkles and rainbows, 16 args, no delay:
- 0x03, 0x1d, 0x07, 0x06,
- 0x2E, 0x2C, 0x29, 0x2D,
- 0x2E, 0x2E, 0x37, 0x3F,
- 0x00, 0x00, 0x02, 0x10,
- ST7735_NORON , DELAY, // 3: Normal display on, no args, w/delay
- 10, // 10 ms delay
- ST7735_DISPON , DELAY, // 4: Main screen turn on, no args w/delay
- 100 }; // 100 ms delay
-
-
- // Companion code to the above tables. Reads and issues
- // a series of LCD commands stored in PROGMEM byte array.
- void ST7735_t3::commandList(const uint8_t *addr)
- {
- uint8_t numCommands, numArgs;
- uint16_t ms;
-
- beginSPITransaction();
- numCommands = pgm_read_byte(addr++); // Number of commands to follow
- //Serial.printf("CommandList: numCmds:%d\n", numCommands); Serial.flush();
- while(numCommands--) { // For each command...
- writecommand_last(pgm_read_byte(addr++)); // Read, issue command
- numArgs = pgm_read_byte(addr++); // Number of args to follow
- ms = numArgs & DELAY; // If hibit set, delay follows args
- numArgs &= ~DELAY; // Mask out delay bit
- while(numArgs > 1) { // For each argument...
- writedata(pgm_read_byte(addr++)); // Read, issue argument
- numArgs--;
- }
-
- if (numArgs) writedata_last(pgm_read_byte(addr++)); // Read, issue argument - wait until this one completes
- if(ms) {
- ms = pgm_read_byte(addr++); // Read post-command delay time (ms)
- if(ms == 255) ms = 500; // If 255, delay for 500 ms
- //Serial.printf("delay %d\n", ms); Serial.flush();
- endSPITransaction();
- delay(ms);
- beginSPITransaction();
- }
- }
- endSPITransaction();
- }
-
-
- // Initialization code common to both 'B' and 'R' type displays
- void ST7735_t3::commonInit(const uint8_t *cmdList, uint8_t mode)
- {
- _colstart = _rowstart = 0; // May be overridden in init func
- _ystart = _xstart = 0;
-
- #if defined(__MK20DX128__) || defined(__MK20DX256__) || defined(__MK64FX512__) || defined(__MK66FX1M0__)
- if (_sid == (uint8_t)-1) _sid = 11;
- if (_sclk == (uint8_t)-1) _sclk = 13;
-
- // Lets try to handle cases where DC is not hardware, without going all the way down to bit bang!
- //if (SPI.pinIsMOSI(_sid) && SPI.pinIsSCK(_sclk) && SPI.pinIsChipSelect(_rs)) {
- if (SPI.pinIsMOSI(_sid) && SPI.pinIsSCK(_sclk)) {
- _pspi = &SPI;
- _spi_num = 0; // Which buss is this spi on?
- _pkinetisk_spi = &KINETISK_SPI0; // Could hack our way to grab this from SPI object, but...
- _fifo_full_test = (3 << 12);
- //Serial.println("ST7735_t3::commonInit SPI");
-
- #if defined(__MK64FX512__) || defined(__MK66FX1M0__)
- } else if (SPI1.pinIsMOSI(_sid) && SPI1.pinIsSCK(_sclk)) {
- _pspi = &SPI1;
- _spi_num = 1; // Which buss is this spi on?
-
- _pkinetisk_spi = &KINETISK_SPI1;
- _fifo_full_test = (0 << 12);
- //Serial.println("ST7735_t3::commonInit SPI1");
- } else if (SPI2.pinIsMOSI(_sid) && SPI2.pinIsSCK(_sclk)) {
- _pspi = &SPI2;
- _spi_num = 2; // Which buss is this spi on?
- _pkinetisk_spi = &KINETISK_SPI2;
- _fifo_full_test = (0 << 12);
- //Serial.println("ST7735_t3::commonInit SPI2");
- #endif
- } else _pspi = nullptr;
-
- if (_pspi) {
- hwSPI = true;
- _pspi->setMOSI(_sid);
- _pspi->setSCK(_sclk);
- _pspi->begin();
- //Serial.println("After SPI begin");
- _spiSettings = SPISettings(ST7735_SPICLOCK, MSBFIRST, mode);
- // See if both CS and DC are valid CS pins.
- if (_pspi->pinIsChipSelect(_rs, _cs)) {
- pcs_data = _pspi->setCS(_cs);
- pcs_command = pcs_data | _pspi->setCS(_rs);
- cspin = 0; // Let know that we are not setting manual
- //Serial.println("Both CS and DC are SPI pins");
- // See if at least DC is hardware CS...
- } else if (_pspi->pinIsChipSelect(_rs)) {
- // We already verified that _rs was valid CS pin above.
- pcs_data = 0;
- pcs_command = pcs_data | _pspi->setCS(_rs);
- if (_cs != 0xff) {
- pinMode(_cs, OUTPUT);
- cspin = portOutputRegister(digitalPinToPort(_cs));
- *cspin = 1;
- }
- } else {
- // DC is not, and won't bother to check CS...
- pcs_data = 0;
- pcs_command = 0;
- if (_cs != 0xff) {
- pinMode(_cs, OUTPUT);
- cspin = portOutputRegister(digitalPinToPort(_cs));
- *cspin = 1;
- }
- pinMode(_rs, OUTPUT);
- rspin = portOutputRegister(digitalPinToPort(_rs));
- *rspin = 0;
- // Pass 1, now lets set hwSPI false
- hwSPI = false;
- }
- // Hack to get hold of the SPI Hardware information...
- uint32_t *pa = (uint32_t*)((void*)_pspi);
- _spi_hardware = (SPIClass::SPI_Hardware_t*)(void*)pa[1];
- } else {
- //Serial.println("ST7735_t3::commonInit Software SPI :(");
- hwSPI = false;
- _pspi = nullptr;
- cspin = (_cs != 0xff)? portOutputRegister(digitalPinToPort(_cs)) : 0;
- rspin = portOutputRegister(digitalPinToPort(_rs));
- clkpin = portOutputRegister(digitalPinToPort(_sclk));
- datapin = portOutputRegister(digitalPinToPort(_sid));
- *cspin = 1;
- *rspin = 0;
- *clkpin = 0;
- *datapin = 0;
- if (_cs != 0xff) pinMode(_cs, OUTPUT);
- pinMode(_rs, OUTPUT);
- pinMode(_sclk, OUTPUT);
- pinMode(_sid, OUTPUT);
- }
- // Teensy 4
- #elif defined(__IMXRT1062__) // Teensy 4.x
- if (_sid == (uint8_t)-1) _sid = 11;
- if (_sclk == (uint8_t)-1) _sclk = 13;
- if (SPI.pinIsMOSI(_sid) && SPI.pinIsSCK(_sclk)) {
- _pspi = &SPI;
- _spi_num = 0; // Which buss is this spi on?
- _pimxrt_spi = &IMXRT_LPSPI4_S; // Could hack our way to grab this from SPI object, but...
-
- } else if (SPI1.pinIsMOSI(_sid) && SPI1.pinIsSCK(_sclk)) {
- _pspi = &SPI1;
- _spi_num = 1; // Which buss is this spi on?
- _pimxrt_spi = &IMXRT_LPSPI3_S;
- } else if (SPI2.pinIsMOSI(_sid) && SPI2.pinIsSCK(_sclk)) {
- _pspi = &SPI2;
- _spi_num = 2; // Which buss is this spi on?
- _pimxrt_spi = &IMXRT_LPSPI1_S;
- } else _pspi = nullptr;
-
- if (_pspi) {
- hwSPI = true;
- _pspi->begin();
- _pending_rx_count = 0;
- _spiSettings = SPISettings(ST7735_SPICLOCK, MSBFIRST, mode);
- _pspi->beginTransaction(_spiSettings); // Should have our settings.
- _pspi->transfer(0); // hack to see if it will actually change then...
- _pspi->endTransaction();
- _spi_tcr_current = _pimxrt_spi->TCR; // get the current TCR value
- // uint32_t *phack = (uint32_t* )&_spiSettings;
- // Serial.printf("SPI Settings: TCR: %x %x (%x %x)\n", _spi_tcr_current, _pimxrt_spi->TCR, phack[0], phack[1]);
- // Hack to get hold of the SPI Hardware information...
- uint32_t *pa = (uint32_t*)((void*)_pspi);
- _spi_hardware = (SPIClass::SPI_Hardware_t*)(void*)pa[1];
-
- } else {
- hwSPI = false;
- _sckport = portOutputRegister(_sclk);
- _sckpinmask = digitalPinToBitMask(_sclk);
- pinMode(_sclk, OUTPUT);
- DIRECT_WRITE_LOW(_sckport, _sckpinmask);
-
- _mosiport = portOutputRegister(_sid);
- _mosipinmask = digitalPinToBitMask(_sid);
- pinMode(_sid, OUTPUT);
- DIRECT_WRITE_LOW(_mosiport, _mosipinmask);
-
- }
- if (_cs != 0xff) {
- _csport = portOutputRegister(_cs);
- _cspinmask = digitalPinToBitMask(_cs);
- pinMode(_cs, OUTPUT);
- DIRECT_WRITE_HIGH(_csport, _cspinmask);
- } else _csport = 0;
-
- if (_pspi && _pspi->pinIsChipSelect(_rs)) {
- uint8_t dc_cs_index = _pspi->setCS(_rs);
- _dcport = 0;
- _dcpinmask = 0;
- dc_cs_index--; // convert to 0 based
- _tcr_dc_assert = LPSPI_TCR_PCS(dc_cs_index);
- _tcr_dc_not_assert = LPSPI_TCR_PCS(3);
- } else {
- //Serial.println("ST7735_t3: Error not DC is not valid hardware CS pin");
- _dcport = portOutputRegister(_rs);
- _dcpinmask = digitalPinToBitMask(_rs);
- pinMode(_rs, OUTPUT);
- DIRECT_WRITE_HIGH(_dcport, _dcpinmask);
- _tcr_dc_assert = LPSPI_TCR_PCS(0);
- _tcr_dc_not_assert = LPSPI_TCR_PCS(1);
- }
- maybeUpdateTCR(_tcr_dc_not_assert | LPSPI_TCR_FRAMESZ(7));
-
- // Teensy LC
- #elif defined(__MKL26Z64__)
- hwSPI1 = false;
- if (_sid == (uint8_t)-1) _sid = 11;
- if (_sclk == (uint8_t)-1) _sclk = 13;
-
- // See if pins are on standard SPI0
- if ((_sid == 7 || _sid == 11) && (_sclk == 13 || _sclk == 14)) {
- hwSPI = true;
- } else {
- hwSPI = false;
- if ((_sid == 0 || _sid == 21) && (_sclk == 20 )) {
- hwSPI1 = true;
- }
- }
-
- if (_cs != 0xff) {
- pinMode(_cs, OUTPUT);
- csport = portOutputRegister(digitalPinToPort(_cs));
- cspinmask = digitalPinToBitMask(_cs);
- } else csport = 0;
-
- pinMode(_rs, OUTPUT);
- rsport = portOutputRegister(digitalPinToPort(_rs));
- rspinmask = digitalPinToBitMask(_rs);
- _spiSettings = SPISettings(ST7735_SPICLOCK, MSBFIRST, mode);
-
- if(hwSPI) { // Using hardware SPI
- if (_sclk == 14) SPI.setSCK(14);
- if (_sid == 7) SPI.setMOSI(7);
- SPI.begin();
- } else if(hwSPI1) { // Using hardware SPI
- SPI1.setSCK(_sclk);
- SPI1.setMOSI(_sid);
- SPI1.begin();
- } else {
- pinMode(_sclk, OUTPUT);
- pinMode(_sid , OUTPUT);
- clkport = portOutputRegister(digitalPinToPort(_sclk));
- dataport = portOutputRegister(digitalPinToPort(_sid));
- clkpinmask = digitalPinToBitMask(_sclk);
- datapinmask = digitalPinToBitMask(_sid);
- *clkport &= ~clkpinmask;
- *dataport &= ~datapinmask;
- }
- // toggle RST low to reset; CS low so it'll listen to us
- *csport &= ~cspinmask;
-
- #endif
- // BUGBUG
- // digitalWrite(_cs, LOW);
- if (_rst != 0xff) {
- pinMode(_rst, OUTPUT);
- digitalWrite(_rst, HIGH);
- delay(100);
- digitalWrite(_rst, LOW);
- delay(100);
- digitalWrite(_rst, HIGH);
- delay(200);
- }
-
- if(cmdList) commandList(cmdList);
- }
-
-
- // Initialization for ST7735B screens
- void ST7735_t3::initB(void)
- {
- commonInit(Bcmd);
- }
-
-
- // Initialization for ST7735R screens (green or red tabs)
- void ST7735_t3::initR(uint8_t options)
- {
- commonInit(Rcmd1);
- if (options == INITR_GREENTAB) {
- commandList(Rcmd2green);
- _colstart = 2;
- _rowstart = 1;
- } else if(options == INITR_144GREENTAB) {
- _screenHeight = ST7735_TFTHEIGHT_144;
- commandList(Rcmd2green144);
- _colstart = 2;
- _rowstart = 3;
- } else if(options == INITR_144GREENTAB_OFFSET) {
- _screenHeight = ST7735_TFTHEIGHT_144;
- commandList(Rcmd2green144);
- _colstart = 0;
- _rowstart = 32;
- } else if(options == INITR_MINI160x80) {
- _screenHeight = ST7735_TFTHEIGHT_160;
- _screenWidth = ST7735_TFTWIDTH_80;
- commandList(Rcmd2green160x80);
- _colstart = 24;
- _rowstart = 0;
- } else if (options == INITR_MINI160x80_ST7735S) {
- _screenHeight = 160;
- _screenWidth = 80;
- commandList(Rcmd2minist7735s);
- _colstart = 26;
- _rowstart = 1;
- } else {
- // _colstart, _rowstart left at default '0' values
- commandList(Rcmd2red);
- }
- commandList(Rcmd3);
-
- // if black or mini, change MADCTL color filter
- if ((options == INITR_BLACKTAB) || (options == INITR_MINI160x80)){
- writecommand(ST7735_MADCTL);
- writedata_last(0xC0);
- }
-
- tabcolor = options;
- setRotation(0);
-
- }
-
-
- void ST7735_t3::setAddrWindow(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1)
- {
- beginSPITransaction();
- setAddr(x0, y0, x1, y1);
- writecommand(ST7735_RAMWR); // write to RAM
- // The setAddrWindow/pushColor will only work if SPI is kept active during this loop...
- endSPITransaction();
- }
-
-
- void ST7735_t3::pushColor(uint16_t color, boolean last_pixel)
- {
- //beginSPITransaction();
- if (last_pixel) {
- writedata16_last(color);
- endSPITransaction();
- } else {
- writedata16(color);
- }
- }
-
- //#include "glcdfont.c"
- extern "C" const unsigned char glcdfont[];
-
-
- void ST7735_t3::drawPixel(int16_t x, int16_t y, uint16_t color)
- {
- x += _originx;
- y += _originy;
-
- if((x < _displayclipx1) ||(x >= _displayclipx2) || (y < _displayclipy1) || (y >= _displayclipy2)) return;
-
- #ifdef ENABLE_ST77XX_FRAMEBUFFER
- if (_use_fbtft) {
- _pfbtft[y*_width + x] = color;
-
- } else
- #endif
- {
- beginSPITransaction();
- setAddr(x,y,x+1,y+1);
- writecommand(ST7735_RAMWR);
- writedata16_last(color);
- endSPITransaction();
- }
- }
-
-
- void ST7735_t3::drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color)
- {
- x+=_originx;
- y+=_originy;
- // Rectangular clipping
- if((x < _displayclipx1) || (x >= _displayclipx2) || (y >= _displayclipy2)) return;
- if(y < _displayclipy1) { h = h - (_displayclipy1 - y); y = _displayclipy1;}
- if((y+h-1) >= _displayclipy2) h = _displayclipy2-y;
- if(h<1) return;
-
- #ifdef ENABLE_ST77XX_FRAMEBUFFER
- if (_use_fbtft) {
- uint16_t * pfbPixel = &_pfbtft[ y*_width + x];
- while (h--) {
- *pfbPixel = color;
- pfbPixel += _width;
- }
- } else
- #endif
- {
- beginSPITransaction();
- setAddr(x, y, x, y+h-1);
- writecommand(ST7735_RAMWR);
- while (h-- > 1) {
- writedata16(color);
- }
- writedata16_last(color);
- endSPITransaction();
- }
- }
-
-
- void ST7735_t3::drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color)
- {
- x+=_originx;
- y+=_originy;
-
- // Rectangular clipping
- if((y < _displayclipy1) || (x >= _displayclipx2) || (y >= _displayclipy2)) return;
- if(x<_displayclipx1) { w = w - (_displayclipx1 - x); x = _displayclipx1; }
- if((x+w-1) >= _displayclipx2) w = _displayclipx2-x;
- if (w<1) return;
-
- #ifdef ENABLE_ST77XX_FRAMEBUFFER
- if (_use_fbtft) {
- if ((x&1) || (w&1)) {
- uint16_t * pfbPixel = &_pfbtft[ y*_width + x];
- while (w--) {
- *pfbPixel++ = color;
- }
- } else {
- // X is even and so is w, try 32 bit writes..
- uint32_t color32 = (color << 16) | color;
- uint32_t * pfbPixel = (uint32_t*)((uint16_t*)&_pfbtft[ y*_width + x]);
- while (w) {
- *pfbPixel++ = color32;
- w -= 2;
- }
- }
- } else
- #endif
- {
- beginSPITransaction();
- setAddr(x, y, x+w-1, y);
- writecommand(ST7735_RAMWR);
- while (w-- > 1) {
- writedata16(color);
- }
- writedata16_last(color);
- endSPITransaction();
- }
- }
-
- void ST7735_t3::fillScreen(uint16_t color)
- {
- fillRect(0, 0, _width, _height, color);
- }
-
- // fill a rectangle
- void ST7735_t3::fillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color)
- {
- x+=_originx;
- y+=_originy;
-
- // Rectangular clipping (drawChar w/big text requires this)
- if((x >= _displayclipx2) || (y >= _displayclipy2)) return;
- if (((x+w) <= _displayclipx1) || ((y+h) <= _displayclipy1)) return;
- if(x < _displayclipx1) { w -= (_displayclipx1-x); x = _displayclipx1; }
- if(y < _displayclipy1) { h -= (_displayclipy1 - y); y = _displayclipy1; }
- if((x + w - 1) >= _displayclipx2) w = _displayclipx2 - x;
- if((y + h - 1) >= _displayclipy2) h = _displayclipy2 - y;
-
- #ifdef ENABLE_ST77XX_FRAMEBUFFER
- if (_use_fbtft) {
- if ((x&1) || (w&1)) {
- uint16_t * pfbPixel_row = &_pfbtft[ y*_width + x];
- for (;h>0; h--) {
- uint16_t * pfbPixel = pfbPixel_row;
- for (int i = 0 ;i < w; i++) {
- *pfbPixel++ = color;
- }
- pfbPixel_row += _width;
- }
- } else {
- // Horizontal is even number so try 32 bit writes instead
- uint32_t color32 = (color << 16) | color;
- uint32_t * pfbPixel_row = (uint32_t *)((uint16_t*)&_pfbtft[ y*_width + x]);
- w = w/2; // only iterate half the times
- for (;h>0; h--) {
- uint32_t * pfbPixel = pfbPixel_row;
- for (int i = 0 ;i < w; i++) {
- *pfbPixel++ = color32;
- }
- pfbPixel_row += (_width/2);
- }
- }
- } else
- #endif
- {
-
- // TODO: this can result in a very long transaction time
- // should break this into multiple transactions, even though
- // it'll cost more overhead, so we don't stall other SPI libs
- beginSPITransaction();
- setAddr(x, y, x+w-1, y+h-1);
- writecommand(ST7735_RAMWR);
- for(y=h; y>0; y--) {
- for(x=w; x>1; x--) {
- writedata16(color);
- }
- writedata16_last(color);
- }
- endSPITransaction();
- }
- }
-
-
- #define MADCTL_MY 0x80
- #define MADCTL_MX 0x40
- #define MADCTL_MV 0x20
- #define MADCTL_ML 0x10
- #define MADCTL_RGB 0x00
- #define MADCTL_BGR 0x08
- #define MADCTL_MH 0x04
-
- void ST7735_t3::setRotation(uint8_t m)
- {
- //Serial.printf("Setting Rotation to %d\n", m);
- beginSPITransaction();
- writecommand(ST7735_MADCTL);
- rotation = m % 4; // can't be higher than 3
- switch (rotation) {
- case 0:
- if ((tabcolor == INITR_BLACKTAB) || (tabcolor == INITR_MINI160x80)) {
- writedata_last(MADCTL_MX | MADCTL_MY | MADCTL_RGB);
- } else {
- writedata_last(MADCTL_MX | MADCTL_MY | MADCTL_BGR);
- }
- _width = _screenWidth;
- _height = _screenHeight;
- _xstart = _colstart;
- _ystart = _rowstart;
- break;
- case 1:
- if ((tabcolor == INITR_BLACKTAB) || (tabcolor == INITR_MINI160x80)) {
- writedata_last(MADCTL_MY | MADCTL_MV | MADCTL_RGB);
- } else {
- writedata_last(MADCTL_MY | MADCTL_MV | MADCTL_BGR);
- }
- _height = _screenWidth;
- _width = _screenHeight;
- _ystart = _colstart;
- _xstart = _rowstart;
- break;
- case 2:
- if ((tabcolor == INITR_BLACKTAB) || (tabcolor == INITR_MINI160x80)) {
- writedata_last(MADCTL_RGB);
- } else {
- writedata_last(MADCTL_BGR);
- }
- _width = _screenWidth;
- _height = _screenHeight;
- _xstart = _colstart;
- // hack to make work on a couple different displays
- _ystart = (_rowstart==0 || _rowstart==32)? 0 : 1;//_rowstart;
- break;
- case 3:
- if ((tabcolor == INITR_BLACKTAB) || (tabcolor == INITR_MINI160x80)) {
- writedata_last(MADCTL_MX | MADCTL_MV | MADCTL_RGB);
- } else {
- writedata_last(MADCTL_MX | MADCTL_MV | MADCTL_BGR);
- }
- _width = _screenHeight;
- _height = _screenWidth;
- _ystart = _colstart;
- // hack to make work on a couple different displays
- _xstart = (_rowstart==0 || _rowstart==32)? 0 : 1;//_rowstart;
- break;
- }
- _rot = rotation; // remember the rotation...
- endSPITransaction();
-
- //Serial.printf("SetRotation(%d) _xstart=%d _ystart=%d _width=%d, _height=%d\n", _rot, _xstart, _ystart, _width, _height);
-
-
- setClipRect();
- setOrigin();
-
- cursor_x = 0;
- cursor_y = 0;
- }
-
- void ST7735_t3::setRowColStart(uint16_t x, uint16_t y) {
- _rowstart = x;
- _colstart = y;
- if (_rot != 0xff) setRotation(_rot);
- }
-
-
- void ST7735_t3::invertDisplay(boolean i)
- {
- beginSPITransaction();
- writecommand_last(i ? ST7735_INVON : ST7735_INVOFF);
- endSPITransaction();
-
- }
-
- /*!
- @brief Adafruit_SPITFT Send Command handles complete sending of commands and const data
- @param commandByte The Command Byte
- @param dataBytes A pointer to the Data bytes to send
- @param numDataBytes The number of bytes we should send
- */
- void ST7735_t3::sendCommand(uint8_t commandByte, const uint8_t *dataBytes, uint8_t numDataBytes) {
- beginSPITransaction();
-
- writecommand_last(commandByte); // Send the command byte
-
- while (numDataBytes > 1) {
- writedata(*dataBytes++); // Send the data bytes
- numDataBytes--;
- }
- if (numDataBytes) writedata_last(*dataBytes);
-
- endSPITransaction();
- }
-
- uint16_t ST7735_t3::readPixel(int16_t x, int16_t y)
- {
- uint16_t colors = 0;
- readRect(x, y, 1, 1, &colors);
- return colors;
- }
-
-
- // Now lets see if we can read in multiple pixels
- void ST7735_t3::readRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t *pcolors)
- {
- // Use our Origin.
- x+=_originx;
- y+=_originy;
- //BUGBUG:: Should add some validation of X and Y
-
- #ifdef ENABLE_ST77XX_FRAMEBUFFER
- if (_use_fbtft) {
- uint16_t * pfbPixel_row = &_pfbtft[ y*_width + x];
- for (;h>0; h--) {
- uint16_t * pfbPixel = pfbPixel_row;
- for (int i = 0 ;i < w; i++) {
- *pcolors++ = *pfbPixel++;
- }
- pfbPixel_row += _width;
- }
- return;
- }
- #endif
- }
-
- // Now lets see if we can writemultiple pixels
- void ST7735_t3::writeRect(int16_t x, int16_t y, int16_t w, int16_t h, const uint16_t *pcolors)
- {
- x+=_originx;
- y+=_originy;
-
- uint16_t x_clip_left = 0; // How many entries at start of colors to skip at start of row
- uint16_t x_clip_right = 0; // how many color entries to skip at end of row for clipping
- // Rectangular clipping
-
- // See if the whole thing out of bounds...
- if((x >= _displayclipx2) || (y >= _displayclipy2)) return;
- if (((x+w) <= _displayclipx1) || ((y+h) <= _displayclipy1)) return;
-
- // In these cases you can not do simple clipping, as we need to synchronize the colors array with the
- // We can clip the height as when we get to the last visible we don't have to go any farther.
- // also maybe starting y as we will advance the color array.
- if(y < _displayclipy1) {
- int dy = (_displayclipy1 - y);
- h -= dy;
- pcolors += (dy*w); // Advance color array to
- y = _displayclipy1;
- }
- if((y + h - 1) >= _displayclipy2) h = _displayclipy2 - y;
- // For X see how many items in color array to skip at start of row and likewise end of row
- if(x < _displayclipx1) {
- x_clip_left = _displayclipx1-x;
- w -= x_clip_left;
- x = _displayclipx1;
- }
-
- if((x + w - 1) >= _displayclipx2) {
- x_clip_right = w;
- w = _displayclipx2 - x;
- x_clip_right -= w;
- }
-
- #ifdef ENABLE_ST77XX_FRAMEBUFFER
- if (_use_fbtft) {
- uint16_t * pfbPixel_row = &_pfbtft[ y*_width + x];
- for (;h>0; h--) {
- uint16_t * pfbPixel = pfbPixel_row;
- pcolors += x_clip_left;
- for (int i = 0 ;i < w; i++) {
- *pfbPixel++ = *pcolors++;
- }
- pfbPixel_row += _width;
- pcolors += x_clip_right;
-
- }
- return;
- }
- #endif
-
- beginSPITransaction();
- setAddr(x, y, x+w-1, y+h-1);
- writecommand(ST7735_RAMWR);
- for(y=h; y>0; y--) {
- pcolors += x_clip_left;
- for(x=w; x>1; x--) {
- writedata16(*pcolors++);
- }
- writedata16_last(*pcolors++);
- pcolors += x_clip_right;
- }
- endSPITransaction();
- }
-
- ///
- ///
- ///
- // Draw a rectangle
- void ST7735_t3::drawRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color)
- {
-
- drawFastHLine(x, y, w, color);
- drawFastHLine(x, y+h-1, w, color);
- drawFastVLine(x, y, h, color);
- drawFastVLine(x+w-1, y, h, color);
- }
-
- // Draw a rounded rectangle
- void ST7735_t3::drawRoundRect(int16_t x, int16_t y, int16_t w,
- int16_t h, int16_t r, uint16_t color) {
- // smarter version
- drawFastHLine(x+r , y , w-2*r, color); // Top
- drawFastHLine(x+r , y+h-1, w-2*r, color); // Bottom
- drawFastVLine(x , y+r , h-2*r, color); // Left
- drawFastVLine(x+w-1, y+r , h-2*r, color); // Right
- // draw four corners
- drawCircleHelper(x+r , y+r , r, 1, color);
- drawCircleHelper(x+w-r-1, y+r , r, 2, color);
- drawCircleHelper(x+w-r-1, y+h-r-1, r, 4, color);
- drawCircleHelper(x+r , y+h-r-1, r, 8, color);
- }
-
- // Fill a rounded rectangle
- void ST7735_t3::fillRoundRect(int16_t x, int16_t y, int16_t w,
- int16_t h, int16_t r, uint16_t color) {
- // smarter version
- fillRect(x+r, y, w-2*r, h, color);
-
- // draw four corners
- fillCircleHelper(x+w-r-1, y+r, r, 1, h-2*r-1, color);
- fillCircleHelper(x+r , y+r, r, 2, h-2*r-1, color);
- }
-
- // Draw a triangle
- void ST7735_t3::drawTriangle(int16_t x0, int16_t y0,
- int16_t x1, int16_t y1,
- int16_t x2, int16_t y2, uint16_t color) {
- drawLine(x0, y0, x1, y1, color);
- drawLine(x1, y1, x2, y2, color);
- drawLine(x2, y2, x0, y0, color);
- }
-
- // Fill a triangle
- void ST7735_t3::fillTriangle ( int16_t x0, int16_t y0,
- int16_t x1, int16_t y1,
- int16_t x2, int16_t y2, uint16_t color) {
-
- int16_t a, b, y, last;
-
- // Sort coordinates by Y order (y2 >= y1 >= y0)
- if (y0 > y1) {
- st7735_swap(y0, y1); st7735_swap(x0, x1);
- }
- if (y1 > y2) {
- st7735_swap(y2, y1); st7735_swap(x2, x1);
- }
- if (y0 > y1) {
- st7735_swap(y0, y1); st7735_swap(x0, x1);
- }
-
- if(y0 == y2) { // Handle awkward all-on-same-line case as its own thing
- a = b = x0;
- if(x1 < a) a = x1;
- else if(x1 > b) b = x1;
- if(x2 < a) a = x2;
- else if(x2 > b) b = x2;
- drawFastHLine(a, y0, b-a+1, color);
- return;
- }
-
- int32_t
- dx01 = x1 - x0,
- dy01 = y1 - y0,
- dx02 = x2 - x0,
- dy02 = y2 - y0,
- dx12 = x2 - x1,
- dy12 = y2 - y1,
- sa = 0,
- sb = 0;
-
- // For upper part of triangle, find scanline crossings for segments
- // 0-1 and 0-2. If y1=y2 (flat-bottomed triangle), the scanline y1
- // is included here (and second loop will be skipped, avoiding a /0
- // error there), otherwise scanline y1 is skipped here and handled
- // in the second loop...which also avoids a /0 error here if y0=y1
- // (flat-topped triangle).
- if(y1 == y2) last = y1; // Include y1 scanline
- else last = y1-1; // Skip it
-
- for(y=y0; y<=last; y++) {
- a = x0 + sa / dy01;
- b = x0 + sb / dy02;
- sa += dx01;
- sb += dx02;
- /* longhand:
- a = x0 + (x1 - x0) * (y - y0) / (y1 - y0);
- b = x0 + (x2 - x0) * (y - y0) / (y2 - y0);
- */
- if(a > b) st7735_swap(a,b);
- drawFastHLine(a, y, b-a+1, color);
- }
-
- // For lower part of triangle, find scanline crossings for segments
- // 0-2 and 1-2. This loop is skipped if y1=y2.
- sa = dx12 * (y - y1);
- sb = dx02 * (y - y0);
- for(; y<=y2; y++) {
- a = x1 + sa / dy12;
- b = x0 + sb / dy02;
- sa += dx12;
- sb += dx02;
- /* longhand:
- a = x1 + (x2 - x1) * (y - y1) / (y2 - y1);
- b = x0 + (x2 - x0) * (y - y0) / (y2 - y0);
- */
- if(a > b) st7735_swap(a,b);
- drawFastHLine(a, y, b-a+1, color);
- }
- }
-
- // Draw a circle outline
- void ST7735_t3::drawCircle(int16_t x0, int16_t y0, int16_t r,
- uint16_t color) {
- int16_t f = 1 - r;
- int16_t ddF_x = 1;
- int16_t ddF_y = -2 * r;
- int16_t x = 0;
- int16_t y = r;
-
- drawPixel(x0 , y0+r, color);
- drawPixel(x0 , y0-r, color);
- drawPixel(x0+r, y0 , color);
- drawPixel(x0-r, y0 , color);
-
- while (x<y) {
- if (f >= 0) {
- y--;
- ddF_y += 2;
- f += ddF_y;
- }
- x++;
- ddF_x += 2;
- f += ddF_x;
-
- drawPixel(x0 + x, y0 + y, color);
- drawPixel(x0 - x, y0 + y, color);
- drawPixel(x0 + x, y0 - y, color);
- drawPixel(x0 - x, y0 - y, color);
- drawPixel(x0 + y, y0 + x, color);
- drawPixel(x0 - y, y0 + x, color);
- drawPixel(x0 + y, y0 - x, color);
- drawPixel(x0 - y, y0 - x, color);
- }
- }
-
- void ST7735_t3::drawCircleHelper( int16_t x0, int16_t y0,
- int16_t r, uint8_t cornername, uint16_t color) {
- int16_t f = 1 - r;
- int16_t ddF_x = 1;
- int16_t ddF_y = -2 * r;
- int16_t x = 0;
- int16_t y = r;
-
- while (x<y) {
- if (f >= 0) {
- y--;
- ddF_y += 2;
- f += ddF_y;
- }
- x++;
- ddF_x += 2;
- f += ddF_x;
- if (cornername & 0x4) {
- drawPixel(x0 + x, y0 + y, color);
- drawPixel(x0 + y, y0 + x, color);
- }
- if (cornername & 0x2) {
- drawPixel(x0 + x, y0 - y, color);
- drawPixel(x0 + y, y0 - x, color);
- }
- if (cornername & 0x8) {
- drawPixel(x0 - y, y0 + x, color);
- drawPixel(x0 - x, y0 + y, color);
- }
- if (cornername & 0x1) {
- drawPixel(x0 - y, y0 - x, color);
- drawPixel(x0 - x, y0 - y, color);
- }
- }
- }
-
- void ST7735_t3::fillCircle(int16_t x0, int16_t y0, int16_t r,
- uint16_t color) {
- drawFastVLine(x0, y0-r, 2*r+1, color);
- fillCircleHelper(x0, y0, r, 3, 0, color);
- }
-
- // Used to do circles and roundrects
- void ST7735_t3::fillCircleHelper(int16_t x0, int16_t y0, int16_t r,
- uint8_t cornername, int16_t delta, uint16_t color) {
-
- int16_t f = 1 - r;
- int16_t ddF_x = 1;
- int16_t ddF_y = -2 * r;
- int16_t x = 0;
- int16_t y = r;
-
- while (x<y) {
- if (f >= 0) {
- y--;
- ddF_y += 2;
- f += ddF_y;
- }
- x++;
- ddF_x += 2;
- f += ddF_x;
-
- if (cornername & 0x1) {
- drawFastVLine(x0+x, y0-y, 2*y+1+delta, color);
- drawFastVLine(x0+y, y0-x, 2*x+1+delta, color);
- }
- if (cornername & 0x2) {
- drawFastVLine(x0-x, y0-y, 2*y+1+delta, color);
- drawFastVLine(x0-y, y0-x, 2*x+1+delta, color);
- }
- }
- }
-
- // Bresenham's algorithm - thx wikpedia
- void ST7735_t3::drawLine(int16_t x0, int16_t y0,
- int16_t x1, int16_t y1, uint16_t color)
- {
- if (y0 == y1) {
- if (x1 > x0) {
- drawFastHLine(x0, y0, x1 - x0 + 1, color);
- } else if (x1 < x0) {
- drawFastHLine(x1, y0, x0 - x1 + 1, color);
- } else {
- drawPixel(x0, y0, color);
- }
- return;
- } else if (x0 == x1) {
- if (y1 > y0) {
- drawFastVLine(x0, y0, y1 - y0 + 1, color);
- } else {
- drawFastVLine(x0, y1, y0 - y1 + 1, color);
- }
- return;
- }
-
- bool steep = abs(y1 - y0) > abs(x1 - x0);
- if (steep) {
- st7735_swap(x0, y0);
- st7735_swap(x1, y1);
- }
- if (x0 > x1) {
- st7735_swap(x0, x1);
- st7735_swap(y0, y1);
- }
-
- int16_t dx, dy;
- dx = x1 - x0;
- dy = abs(y1 - y0);
-
- int16_t err = dx / 2;
- int16_t ystep;
-
- if (y0 < y1) {
- ystep = 1;
- } else {
- ystep = -1;
- }
-
- #ifdef ENABLE_ST77XX_FRAMEBUFFER
- if (!_use_fbtft) beginSPITransaction();
- #else
- beginSPITransaction();
- #endif
- int16_t xbegin = x0;
- if (steep) {
- for (; x0<=x1; x0++) {
- err -= dy;
- if (err < 0) {
- int16_t len = x0 - xbegin;
- if (len) {
- VLine(y0, xbegin, len + 1, color);
- } else {
- Pixel(y0, x0, color);
- }
- xbegin = x0 + 1;
- y0 += ystep;
- err += dx;
- }
- }
- if (x0 > xbegin + 1) {
- VLine(y0, xbegin, x0 - xbegin, color);
- }
-
- } else {
- for (; x0<=x1; x0++) {
- err -= dy;
- if (err < 0) {
- int16_t len = x0 - xbegin;
- if (len) {
- HLine(xbegin, y0, len + 1, color);
- } else {
- Pixel(x0, y0, color);
- }
- xbegin = x0 + 1;
- y0 += ystep;
- err += dx;
- }
- }
- if (x0 > xbegin + 1) {
- HLine(xbegin, y0, x0 - xbegin, color);
- }
- }
- #ifdef ENABLE_ST77XX_FRAMEBUFFER
- if (!_use_fbtft) {
- writecommand_last(ST7735_NOP);
- endSPITransaction();
- }
- #else
- writecommand_last(ST7735_NOP);
- endSPITransaction();
- #endif
- }
-
- void ST7735_t3::drawBitmap(int16_t x, int16_t y,
- const uint8_t *bitmap, int16_t w, int16_t h,
- uint16_t color) {
-
- int16_t i, j, byteWidth = (w + 7) / 8;
-
- for(j=0; j<h; j++) {
- for(i=0; i<w; i++ ) {
- if(pgm_read_byte(bitmap + j * byteWidth + i / 8) & (128 >> (i & 7))) {
- drawPixel(x+i, y+j, color);
- }
- }
- }
- }
-
- void ST7735_t3::setCursor(int16_t x, int16_t y, bool autoCenter) {
- _center_x_text = autoCenter; // remember the state.
- _center_y_text = autoCenter; // remember the state.
- if (x == ST7735_t3::CENTER) {
- _center_x_text = true;
- x = _width/2;
- }
- if (y == ST7735_t3::CENTER) {
- _center_y_text = true;
- y = _height/2;
- }
- if (x < 0) x = 0;
- else if (x >= _width) x = _width - 1;
- cursor_x = x;
- if (y < 0) y = 0;
- else if (y >= _height) y = _height - 1;
- cursor_y = y;
-
- if(x>=scroll_x && x<=(scroll_x+scroll_width) && y>=scroll_y && y<=(scroll_y+scroll_height)){
- isWritingScrollArea = true;
- } else {
- isWritingScrollArea = false;
- }
- _gfx_last_char_x_write = 0; // Don't use cached data here
-
- }
-
- void ST7735_t3::getCursor(int16_t *x, int16_t *y) {
- *x = cursor_x;
- *y = cursor_y;
- }
-
- void ST7735_t3::setTextSize(uint8_t s_x, uint8_t s_y) {
- textsize_x = (s_x > 0) ? s_x : 1;
- textsize_y = (s_y > 0) ? s_y : 1;
- }
-
- uint8_t ST7735_t3::getTextSize() {
- return textsize_x; // bug bug 2 values now
- }
-
- uint8_t ST7735_t3::getTextSizeX() {
- return textsize_x;
- }
- uint8_t ST7735_t3::getTextSizeY() {
- return textsize_y;
- }
-
- void ST7735_t3::setTextColor(uint16_t c) {
- // For 'transparent' background, we'll set the bg
- // to the same as fg instead of using a flag
- textcolor = textbgcolor = c;
- }
-
- void ST7735_t3::setTextColor(uint16_t c, uint16_t b) {
- textcolor = c;
- textbgcolor = b;
- // pre-expand colors for fast alpha-blending later
- textcolorPrexpanded = (textcolor | (textcolor << 16)) & 0b00000111111000001111100000011111;
- textbgcolorPrexpanded = (textbgcolor | (textbgcolor << 16)) & 0b00000111111000001111100000011111;
- }
-
- void ST7735_t3::setTextWrap(boolean w) {
- wrap = w;
- }
-
- boolean ST7735_t3::getTextWrap()
- {
- return wrap;
- }
-
- uint8_t ST7735_t3::getRotation(void) {
- return _rot;
- }
-
-
- /***************************************************************************************
- ** Function name: setTextDatum
- ** Description: Set the text position reference datum
- ***************************************************************************************/
- void ST7735_t3::setTextDatum(uint8_t d)
- {
- textdatum = d;
- }
-
-
- /***************************************************************************************
- ** Function name: drawNumber
- ** Description: draw a long integer
- ***************************************************************************************/
- int16_t ST7735_t3::drawNumber(long long_num, int poX, int poY)
- {
- char str[14];
- ltoa(long_num, str, 10);
- return drawString(str, poX, poY);
- }
-
-
- int16_t ST7735_t3::drawFloat(float floatNumber, int dp, int poX, int poY)
- {
- char str[14]; // Array to contain decimal string
- uint8_t ptr = 0; // Initialise pointer for array
- int8_t digits = 1; // Count the digits to avoid array overflow
- float rounding = 0.5; // Round up down delta
-
- if (dp > 7) dp = 7; // Limit the size of decimal portion
-
- // Adjust the rounding value
- for (uint8_t i = 0; i < dp; ++i) rounding /= 10.0f;
-
- if (floatNumber < -rounding) // add sign, avoid adding - sign to 0.0!
- {
- str[ptr++] = '-'; // Negative number
- str[ptr] = 0; // Put a null in the array as a precaution
- digits = 0; // Set digits to 0 to compensate so pointer value can be used later
- floatNumber = -floatNumber; // Make positive
- }
-
- floatNumber += rounding; // Round up or down
-
- // For error put ... in string and return (all TFT_ILI9341_ESP library fonts contain . character)
- if (floatNumber >= 2147483647) {
- strcpy(str, "...");
- //return drawString(str, poX, poY);
- }
- // No chance of overflow from here on
-
- // Get integer part
- unsigned long temp = (unsigned long)floatNumber;
-
- // Put integer part into array
- ltoa(temp, str + ptr, 10);
-
- // Find out where the null is to get the digit count loaded
- while ((uint8_t)str[ptr] != 0) ptr++; // Move the pointer along
- digits += ptr; // Count the digits
-
- str[ptr++] = '.'; // Add decimal point
- str[ptr] = '0'; // Add a dummy zero
- str[ptr + 1] = 0; // Add a null but don't increment pointer so it can be overwritten
-
- // Get the decimal portion
- floatNumber = floatNumber - temp;
-
- // Get decimal digits one by one and put in array
- // Limit digit count so we don't get a false sense of resolution
- uint8_t i = 0;
- while ((i < dp) && (digits < 9)) // while (i < dp) for no limit but array size must be increased
- {
- i++;
- floatNumber *= 10; // for the next decimal
- temp = floatNumber; // get the decimal
- ltoa(temp, str + ptr, 10);
- ptr++; digits++; // Increment pointer and digits count
- floatNumber -= temp; // Remove that digit
- }
-
- // Finally we can plot the string and return pixel length
- return drawString(str, poX, poY);
- }
-
- /***************************************************************************************
- ** Function name: drawString (with or without user defined font)
- ** Description : draw string with padding if it is defined
- ***************************************************************************************/
- // Without font number, uses font set by setTextFont()
- int16_t ST7735_t3::drawString(const String& string, int poX, int poY)
- {
- int16_t len = string.length() + 2;
- char buffer[len];
- string.toCharArray(buffer, len);
- return drawString1(buffer, len, poX, poY);
- }
-
- int16_t ST7735_t3::drawString1(char string[], int16_t len, int poX, int poY)
- {
- int16_t sumX = 0;
- uint8_t padding = 1/*, baseline = 0*/;
-
- uint16_t cwidth = strPixelLen(string); // Find the pixel width of the string in the font
- uint16_t cheight = textsize_y*8;
-
-
- if (textdatum || padX)
- {
- switch(textdatum) {
- case TC_DATUM:
- poX -= cwidth/2;
- padding += 1;
- break;
- case TR_DATUM:
- poX -= cwidth;
- padding += 2;
- break;
- case ML_DATUM:
- poY -= cheight/2;
- //padding += 0;
- break;
- case MC_DATUM:
- poX -= cwidth/2;
- poY -= cheight/2;
- padding += 1;
- break;
- case MR_DATUM:
- poX -= cwidth;
- poY -= cheight/2;
- padding += 2;
- break;
- case BL_DATUM:
- poY -= cheight;
- //padding += 0;
- break;
- case BC_DATUM:
- poX -= cwidth/2;
- poY -= cheight;
- padding += 1;
- break;
- case BR_DATUM:
- poX -= cwidth;
- poY -= cheight;
- padding += 2;
- break;
- /*
- case L_BASELINE:
- poY -= baseline;
- //padding += 0;
- break;
- case C_BASELINE:
- poX -= cwidth/2;
- poY -= baseline;
- //padding += 1;
- break;
- case R_BASELINE:
- poX -= cwidth;
- poY -= baseline;
- padding += 2;
- break;
- */
- }
- // Check coordinates are OK, adjust if not
- if (poX < 0) poX = 0;
- if (poX+cwidth > width()) poX = width() - cwidth;
- if (poY < 0) poY = 0;
- //if (poY+cheight-baseline >_height) poY = _height - cheight;
- }
- if(font == NULL){
- for(uint8_t i = 0; i < len-2; i++){
- drawChar((int16_t) (poX+sumX), (int16_t) poY, string[i], textcolor, textbgcolor, textsize_x, textsize_y);
- sumX += cwidth/(len-2) + padding;
- }
- } else {
- setCursor(poX, poY);
- for(uint8_t i = 0; i < len-2; i++){
- drawFontChar(string[i]);
- setCursor(cursor_x, cursor_y);
- }
- }
- return sumX;
- }
-
-
- void ST7735_t3::scrollTextArea(uint8_t scrollSize){
- uint16_t awColors[scroll_width];
- for (int y=scroll_y+scrollSize; y < (scroll_y+scroll_height); y++) {
- readRect(scroll_x, y, scroll_width, 1, awColors);
- writeRect(scroll_x, y-scrollSize, scroll_width, 1, awColors);
- }
- fillRect(scroll_x, (scroll_y+scroll_height)-scrollSize, scroll_width, scrollSize, scrollbgcolor);
- }
-
- void ST7735_t3::setScrollTextArea(int16_t x, int16_t y, int16_t w, int16_t h){
- scroll_x = x;
- scroll_y = y;
- scroll_width = w;
- scroll_height = h;
- }
-
- void ST7735_t3::setScrollBackgroundColor(uint16_t color){
- scrollbgcolor=color;
- fillRect(scroll_x,scroll_y,scroll_width,scroll_height,scrollbgcolor);
- }
-
- void ST7735_t3::enableScroll(void){
- scrollEnable = true;
- }
-
- void ST7735_t3::disableScroll(void){
- scrollEnable = false;
- }
-
- void ST7735_t3::resetScrollBackgroundColor(uint16_t color){
- scrollbgcolor=color;
- }
-
-
- // overwrite functions from class Print:
-
- size_t ST7735_t3::write(uint8_t c) {
- return write(&c, 1);
- }
-
- size_t ST7735_t3::write(const uint8_t *buffer, size_t size)
- {
- // Lets try to handle some of the special font centering code that was done for default fonts.
- if (_center_x_text || _center_y_text ) {
- int16_t x, y;
- uint16_t strngWidth, strngHeight;
- getTextBounds(buffer, size, 0, 0, &x, &y, &strngWidth, &strngHeight);
- //Serial.printf("_fontwrite bounds: %d %d %u %u\n", x, y, strngWidth, strngHeight);
- // Note we may want to play with the x ane y returned if they offset some
- if (_center_x_text && strngWidth > 0){//Avoid operations for strngWidth = 0
- cursor_x -= ((x + strngWidth) / 2);
- }
- if (_center_y_text && strngHeight > 0){//Avoid operations for strngWidth = 0
- cursor_y -= ((y + strngHeight) / 2);
- }
- _center_x_text = false;
- _center_y_text = false;
- }
-
- size_t cb = size;
- while (cb) {
- uint8_t c = *buffer++;
- cb--;
-
- if (font) {
- if (c == '\n') {
- cursor_y += font->line_space;
- if(scrollEnable && isWritingScrollArea){
- cursor_x = scroll_x;
- }else{
- cursor_x = 0;
- }
- } else {
- drawFontChar(c);
- }
- } else if (gfxFont) {
- if (c == '\n') {
- cursor_y += (int16_t)textsize_y * gfxFont->yAdvance;
- if(scrollEnable && isWritingScrollArea){
- cursor_x = scroll_x;
- }else{
- cursor_x = 0;
- }
- } else {
- drawGFXFontChar(c);
- }
- } else {
- if (c == '\n') {
- cursor_y += textsize_y*8;
- if(scrollEnable && isWritingScrollArea){
- cursor_x = scroll_x;
- }else{
- cursor_x = 0;
- }
- } else if (c == '\r') {
- // skip em
- } else {
- if(scrollEnable && isWritingScrollArea && (cursor_y > (scroll_y+scroll_height - textsize_y*8))){
- scrollTextArea(textsize_y*8);
- cursor_y -= textsize_y*8;
- cursor_x = scroll_x;
- }
- drawChar(cursor_x, cursor_y, c, textcolor, textbgcolor, textsize_x, textsize_y);
- cursor_x += textsize_x*6;
- if(wrap && scrollEnable && isWritingScrollArea && (cursor_x > (scroll_x+scroll_width - textsize_x*6))){
- cursor_y += textsize_y*8;
- cursor_x = scroll_x;
- }
- else if (wrap && (cursor_x > (_width - textsize_x*6))) {
- cursor_y += textsize_y*8;
- cursor_x = 0;
- }
- }
- }
- }
- return size;
- }
-
- // Draw a character
- void ST7735_t3::drawChar(int16_t x, int16_t y, unsigned char c,
- uint16_t fgcolor, uint16_t bgcolor, uint8_t size_x, uint8_t size_y)
- {
- if((x >= _width) || // Clip right
- (y >= _height) || // Clip bottom
- ((x + 6 * size_x - 1) < 0) || // Clip left TODO: is this correct?
- ((y + 8 * size_y - 1) < 0)) // Clip top TODO: is this correct?
- return;
-
- if (fgcolor == bgcolor) {
- // This transparent approach is only about 20% faster
- if ((size_x == 1) && (size_y == 1)) {
- uint8_t mask = 0x01;
- int16_t xoff, yoff;
- for (yoff=0; yoff < 8; yoff++) {
- uint8_t line = 0;
- for (xoff=0; xoff < 5; xoff++) {
- if (glcdfont[c * 5 + xoff] & mask) line |= 1;
- line <<= 1;
- }
- line >>= 1;
- xoff = 0;
- while (line) {
- if (line == 0x1F) {
- drawFastHLine(x + xoff, y + yoff, 5, fgcolor);
- break;
- } else if (line == 0x1E) {
- drawFastHLine(x + xoff, y + yoff, 4, fgcolor);
- break;
- } else if ((line & 0x1C) == 0x1C) {
- drawFastHLine(x + xoff, y + yoff, 3, fgcolor);
- line <<= 4;
- xoff += 4;
- } else if ((line & 0x18) == 0x18) {
- drawFastHLine(x + xoff, y + yoff, 2, fgcolor);
- line <<= 3;
- xoff += 3;
- } else if ((line & 0x10) == 0x10) {
- drawPixel(x + xoff, y + yoff, fgcolor);
- line <<= 2;
- xoff += 2;
- } else {
- line <<= 1;
- xoff += 1;
- }
- }
- mask = mask << 1;
- }
- } else {
- uint8_t mask = 0x01;
- int16_t xoff, yoff;
- for (yoff=0; yoff < 8; yoff++) {
- uint8_t line = 0;
- for (xoff=0; xoff < 5; xoff++) {
- if (glcdfont[c * 5 + xoff] & mask) line |= 1;
- line <<= 1;
- }
- line >>= 1;
- xoff = 0;
- while (line) {
- if (line == 0x1F) {
- fillRect(x + xoff * size_x, y + yoff * size_y,
- 5 * size_x, size_y, fgcolor);
- break;
- } else if (line == 0x1E) {
- fillRect(x + xoff * size_x, y + yoff * size_y,
- 4 * size_x, size_y, fgcolor);
- break;
- } else if ((line & 0x1C) == 0x1C) {
- fillRect(x + xoff * size_x, y + yoff * size_y,
- 3 * size_x, size_y, fgcolor);
- line <<= 4;
- xoff += 4;
- } else if ((line & 0x18) == 0x18) {
- fillRect(x + xoff * size_x, y + yoff * size_y,
- 2 * size_x, size_y, fgcolor);
- line <<= 3;
- xoff += 3;
- } else if ((line & 0x10) == 0x10) {
- fillRect(x + xoff * size_x, y + yoff * size_y,
- size_x, size_y, fgcolor);
- line <<= 2;
- xoff += 2;
- } else {
- line <<= 1;
- xoff += 1;
- }
- }
- mask = mask << 1;
- }
- }
- } else {
- // This solid background approach is about 5 time faster
- uint8_t xc, yc;
- uint8_t xr, yr;
- uint8_t mask = 0x01;
- uint16_t color;
-
- // We need to offset by the origin.
- x+=_originx;
- y+=_originy;
- int16_t x_char_start = x; // remember our X where we start outputting...
-
- if((x >= _displayclipx2) || // Clip right
- (y >= _displayclipy2) || // Clip bottom
- ((x + 6 * size_x - 1) < _displayclipx1) || // Clip left TODO: this is not correct
- ((y + 8 * size_y - 1) < _displayclipy1)) // Clip top TODO: this is not correct
- return;
-
-
- #ifdef ENABLE_ST77XX_FRAMEBUFFER
- if (_use_fbtft) {
- uint16_t * pfbPixel_row = &_pfbtft[ y*_width + x];
- for (yc=0; (yc < 8) && (y < _displayclipy2); yc++) {
- for (yr=0; (yr < size_y) && (y < _displayclipy2); yr++) {
- x = x_char_start; // get our first x position...
- if (y >= _displayclipy1) {
- uint16_t * pfbPixel = pfbPixel_row;
- for (xc=0; xc < 5; xc++) {
- if (glcdfont[c * 5 + xc] & mask) {
- color = fgcolor;
- } else {
- color = bgcolor;
- }
- for (xr=0; xr < size_x; xr++) {
- if ((x >= _displayclipx1) && (x < _displayclipx2)) {
- *pfbPixel = color;
- }
- pfbPixel++;
- x++;
- }
- }
- for (xr=0; xr < size_x; xr++) {
- if ((x >= _displayclipx1) && (x < _displayclipx2)) {
- *pfbPixel = bgcolor;
- }
- pfbPixel++;
- x++;
- }
- }
- pfbPixel_row += _width; // setup pointer to
- y++;
- }
- mask = mask << 1;
- }
-
- } else
- #endif
- {
- // need to build actual pixel rectangle we will output into.
- int16_t y_char_top = y; // remember the y
- int16_t w = 6 * size_x;
- int16_t h = 8 * size_y;
-
- if(x < _displayclipx1) { w -= (_displayclipx1-x); x = _displayclipx1; }
- if((x + w - 1) >= _displayclipx2) w = _displayclipx2 - x;
- if(y < _displayclipy1) { h -= (_displayclipy1 - y); y = _displayclipy1; }
- if((y + h - 1) >= _displayclipy2) h = _displayclipy2 - y;
-
- beginSPITransaction();
- setAddr(x, y, x + w -1, y + h - 1);
-
- y = y_char_top; // restore the actual y.
- writecommand(ST7735_RAMWR);
- for (yc=0; (yc < 8) && (y < _displayclipy2); yc++) {
- for (yr=0; (yr < size_y) && (y < _displayclipy2); yr++) {
- x = x_char_start; // get our first x position...
- if (y >= _displayclipy1) {
- for (xc=0; xc < 5; xc++) {
- if (glcdfont[c * 5 + xc] & mask) {
- color = fgcolor;
- } else {
- color = bgcolor;
- }
- for (xr=0; xr < size_x; xr++) {
- if ((x >= _displayclipx1) && (x < _displayclipx2)) {
- writedata16(color);
- }
- x++;
- }
- }
- for (xr=0; xr < size_x; xr++) {
- if ((x >= _displayclipx1) && (x < _displayclipx2)) {
- writedata16(bgcolor);
- }
- x++;
- }
- }
- y++;
- }
- mask = mask << 1;
- }
- writecommand_last(ST7735_NOP);
- endSPITransaction();
- }
- }
- }
-
- void ST7735_t3::setFont(const ILI9341_t3_font_t &f) {
- font = &f;
- _gfx_last_char_x_write = 0; // Don't use cached data here
- if (gfxFont) {
- cursor_y -= 6;
- gfxFont = NULL;
- }
- fontbpp = 1;
- // Calculate additional metrics for Anti-Aliased font support (BDF extn v2.3)
- if (font && font->version==23){
- fontbpp = (font->reserved & 0b000011)+1;
- fontbppindex = (fontbpp >> 2)+1;
- fontbppmask = (1 << (fontbppindex+1))-1;
- fontppb = 8/fontbpp;
- fontalphamx = 31/((1<<fontbpp)-1);
- // Ensure text and bg color are different. Note: use setTextColor to set actual bg color
- if (textcolor == textbgcolor) textbgcolor = (textcolor==0x0000)?0xFFFF:0x0000;
- }
- }
-
- // Maybe support GFX Fonts as well?
- void ST7735_t3::setFont(const GFXfont *f) {
- font = NULL; // turn off the other font...
- _gfx_last_char_x_write = 0; // Don't use cached data here
- if (f == gfxFont) return; // same font or lack of so can bail.
-
- if(f) { // Font struct pointer passed in?
- if(!gfxFont) { // And no current font struct?
- // Switching from classic to new font behavior.
- // Move cursor pos down 6 pixels so it's on baseline.
- cursor_y += 6;
- }
-
- // Test wondering high and low of Ys here...
- int8_t miny_offset = 0;
- #if 1
- for (uint8_t i=0; i <= (f->last - f->first); i++) {
- if (f->glyph[i].yOffset < miny_offset) {
- miny_offset = f->glyph[i].yOffset;
- }
- }
- #else
- int max_delta = 0;
- uint8_t index_min = 0;
- uint8_t index_max = 0;
-
- int8_t minx_offset = 127;
- int8_t maxx_overlap = 0;
- uint8_t indexx_min = 0;
- uint8_t indexx_max = 0;
- for (uint8_t i=0; i <= (f->last - f->first); i++) {
- if (f->glyph[i].yOffset < miny_offset) {
- miny_offset = f->glyph[i].yOffset;
- index_min = i;
- }
-
- if (f->glyph[i].xOffset < minx_offset) {
- minx_offset = f->glyph[i].xOffset;
- indexx_min = i;
- }
- if ( (f->glyph[i].yOffset + f->glyph[i].height) > max_delta) {
- max_delta = (f->glyph[i].yOffset + f->glyph[i].height);
- index_max = i;
- }
- int8_t x_overlap = f->glyph[i].xOffset + f->glyph[i].width - f->glyph[i].xAdvance;
- if (x_overlap > maxx_overlap) {
- maxx_overlap = x_overlap;
- indexx_max = i;
- }
- }
- Serial.printf("Set GFX Font(%x): Y: %d %d(%c) %d(%c) X: %d(%c) %d(%c)\n", (uint32_t)f, f->yAdvance,
- miny_offset, index_min + f->first, max_delta, index_max + f->first,
- minx_offset, indexx_min + f->first, maxx_overlap, indexx_max + f->first);
- #endif
- _gfxFont_min_yOffset = miny_offset; // Probably only thing we need... May cache?
-
- } else if(gfxFont) { // NULL passed. Current font struct defined?
- // Switching from new to classic font behavior.
- // Move cursor pos up 6 pixels so it's at top-left of char.
- cursor_y -= 6;
- }
- gfxFont = f;
- }
-
- static uint32_t fetchbit(const uint8_t *p, uint32_t index)
- {
- if (p[index >> 3] & (1 << (7 - (index & 7)))) return 1;
- return 0;
- }
-
- static uint32_t fetchbits_unsigned(const uint8_t *p, uint32_t index, uint32_t required)
- {
- uint32_t val = 0;
- do {
- uint8_t b = p[index >> 3];
- uint32_t avail = 8 - (index & 7);
- if (avail <= required) {
- val <<= avail;
- val |= b & ((1 << avail) - 1);
- index += avail;
- required -= avail;
- } else {
- b >>= avail - required;
- val <<= required;
- val |= b & ((1 << required) - 1);
- break;
- }
- } while (required);
- return val;
- }
-
- static uint32_t fetchbits_signed(const uint8_t *p, uint32_t index, uint32_t required)
- {
- uint32_t val = fetchbits_unsigned(p, index, required);
- if (val & (1 << (required - 1))) {
- return (int32_t)val - (1 << required);
- }
- return (int32_t)val;
- }
-
- uint32_t ST7735_t3::fetchpixel(const uint8_t *p, uint32_t index, uint32_t x)
- {
- // The byte
- uint8_t b = p[index >> 3];
- // Shift to LSB position and mask to get value
- uint8_t s = ((fontppb-(x % fontppb)-1)*fontbpp);
- // Mask and return
- return (b >> s) & fontbppmask;
- }
-
- void ST7735_t3::drawFontChar(unsigned int c)
- {
- uint32_t bitoffset;
- const uint8_t *data;
-
- //Serial.printf("drawFontChar(%c) %d\n", c, c);
-
- if (c >= font->index1_first && c <= font->index1_last) {
- bitoffset = c - font->index1_first;
- bitoffset *= font->bits_index;
- } else if (c >= font->index2_first && c <= font->index2_last) {
- bitoffset = c - font->index2_first + font->index1_last - font->index1_first + 1;
- bitoffset *= font->bits_index;
- } else if (font->unicode) {
- return; // TODO: implement sparse unicode
- } else {
- return;
- }
- //Serial.printf(" index = %d\n", fetchbits_unsigned(font->index, bitoffset, font->bits_index));
- data = font->data + fetchbits_unsigned(font->index, bitoffset, font->bits_index);
-
- uint32_t encoding = fetchbits_unsigned(data, 0, 3);
- if (encoding != 0) return;
- uint32_t width = fetchbits_unsigned(data, 3, font->bits_width);
- bitoffset = font->bits_width + 3;
- uint32_t height = fetchbits_unsigned(data, bitoffset, font->bits_height);
- bitoffset += font->bits_height;
- //Serial.printf(" size = %d,%d\n", width, height);
- //Serial.printf(" line space = %d\n", font->line_space);
-
-
- int32_t xoffset = fetchbits_signed(data, bitoffset, font->bits_xoffset);
- bitoffset += font->bits_xoffset;
- int32_t yoffset = fetchbits_signed(data, bitoffset, font->bits_yoffset);
- bitoffset += font->bits_yoffset;
- //Serial.printf(" offset = %d,%d\n", xoffset, yoffset);
- //Serial.printf("DChar: %c %u, %u, wh:%d %d o:%d %d\n", c, cursor_x, cursor_y, width, height, xoffset, yoffset);
-
- uint32_t delta = fetchbits_unsigned(data, bitoffset, font->bits_delta);
- bitoffset += font->bits_delta;
- //Serial.printf(" delta = %d\n", delta);
-
- //Serial.printf(" cursor = %d,%d\n", cursor_x, cursor_y);
-
- //horizontally, we draw every pixel, or none at all
- if (cursor_x < 0) cursor_x = 0;
- int32_t origin_x = cursor_x + xoffset;
- if (origin_x < 0) {
- cursor_x -= xoffset;
- origin_x = 0;
- }
- if (origin_x + (int)width > _width) {
- if (!wrap) return;
- origin_x = 0;
- if (xoffset >= 0) {
- cursor_x = 0;
- } else {
- cursor_x = -xoffset;
- }
- cursor_y += font->line_space;
- }
- if(wrap && scrollEnable && isWritingScrollArea && ((origin_x + (int)width) > (scroll_x+scroll_width))){
- origin_x = 0;
- if (xoffset >= 0) {
- cursor_x = scroll_x;
- } else {
- cursor_x = -xoffset;
- }
- cursor_y += font->line_space;
- }
-
- if(scrollEnable && isWritingScrollArea && (cursor_y > (scroll_y+scroll_height - font->cap_height))){
- scrollTextArea(font->line_space);
- cursor_y -= font->line_space;
- cursor_x = scroll_x;
- }
- if (cursor_y >= _height) return;
-
- // vertically, the top and/or bottom can be clipped
- int32_t origin_y = cursor_y + font->cap_height - height - yoffset;
- //Serial.printf(" origin = %d,%d\n", origin_x, origin_y);
-
- // TODO: compute top skip and number of lines
- int32_t linecount = height;
- //uint32_t loopcount = 0;
- int32_t y = origin_y;
- bool opaque = (textbgcolor != textcolor);
-
- // Going to try a fast Opaque method which works similar to drawChar, which is near the speed of writerect
- if (!opaque) {
-
- // Anti-alias support
- if (fontbpp>1){
- // This branch should, in most cases, never happen. This is because if an
- // anti-aliased font is being used, textcolor and textbgcolor should always
- // be different. Even though an anti-alised font is being used, pixels in this
- // case will all be solid because pixels are rendered on same colour as themselves!
- // This won't look very good.
- bitoffset = ((bitoffset + 7) & (-8)); // byte-boundary
- uint32_t xp = 0;
- uint8_t halfalpha = 1<<(fontbpp-1);
- while (linecount) {
- uint32_t x = 0;
- while(x<width) {
- // One pixel at a time, either on (if alpha > 0.5) or off
- if (fetchpixel(data, bitoffset, xp)>=halfalpha){
- Pixel(origin_x + x,y,textcolor);
- }
- bitoffset += fontbpp;
- x++;
- xp++;
- }
- y++;
- linecount--;
- }
-
- }
- // Soild pixels
- else{
-
- while (linecount > 0) {
- //Serial.printf(" linecount = %d\n", linecount);
- uint32_t n = 1;
- if (fetchbit(data, bitoffset++) != 0) {
- n = fetchbits_unsigned(data, bitoffset, 3) + 2;
- bitoffset += 3;
- }
- uint32_t x = 0;
- do {
- int32_t xsize = width - x;
- if (xsize > 32) xsize = 32;
- uint32_t bits = fetchbits_unsigned(data, bitoffset, xsize);
- //Serial.printf(" multi line %d %d %x\n", n, x, bits);
- drawFontBits(opaque, bits, xsize, origin_x + x, y, n);
- bitoffset += xsize;
- x += xsize;
- } while (x < width);
-
-
- y += n;
- linecount -= n;
- //if (++loopcount > 100) {
- //Serial.println(" abort draw loop");
- //break;
- //}
- }
- } // 1bpp
- }
-
- // opaque
- else {
- // Now opaque mode...
- // Now write out background color for the number of rows above the above the character
- // figure out bounding rectangle...
- // In this mode we need to update to use the offset and bounding rectangles as we are doing it it direct.
- // also update the Origin
- int cursor_x_origin = cursor_x + _originx;
- int cursor_y_origin = cursor_y + _originy;
- origin_x += _originx;
- origin_y += _originy;
-
- int start_x = (origin_x < cursor_x_origin) ? origin_x : cursor_x_origin;
- if (start_x < 0) start_x = 0;
-
- int start_y = (origin_y < cursor_y_origin) ? origin_y : cursor_y_origin;
- if (start_y < 0) start_y = 0;
- int end_x = cursor_x_origin + delta;
- if ((origin_x + (int)width) > end_x)
- end_x = origin_x + (int)width;
- if (end_x >= _displayclipx2) end_x = _displayclipx2;
- int end_y = cursor_y_origin + font->line_space;
- if ((origin_y + (int)height) > end_y)
- end_y = origin_y + (int)height;
- if (end_y >= _displayclipy2) end_y = _displayclipy2;
- end_x--; // setup to last one we draw
- end_y--;
- int start_x_min = (start_x >= _displayclipx1) ? start_x : _displayclipx1;
- int start_y_min = (start_y >= _displayclipy1) ? start_y : _displayclipy1;
-
- // See if anything is in the display area.
- if((end_x < _displayclipx1) ||(start_x >= _displayclipx2) || (end_y < _displayclipy1) || (start_y >= _displayclipy2)) {
- cursor_x += delta; // could use goto or another indent level...
- return;
- }
- /*
- Serial.printf("drawFontChar(%c) %d\n", c, c);
- Serial.printf(" size = %d,%d\n", width, height);
- Serial.printf(" line space = %d\n", font->line_space);
- Serial.printf(" offset = %d,%d\n", xoffset, yoffset);
- Serial.printf(" delta = %d\n", delta);
- Serial.printf(" cursor = %d,%d\n", cursor_x, cursor_y);
- Serial.printf(" origin = %d,%d\n", origin_x, origin_y);
-
- Serial.printf(" Bounding: (%d, %d)-(%d, %d)\n", start_x, start_y, end_x, end_y);
- Serial.printf(" mins (%d %d),\n", start_x_min, start_y_min);
- */
- #ifdef ENABLE_ST77XX_FRAMEBUFFER
- if (_use_fbtft) {
- uint16_t * pfbPixel_row = &_pfbtft[ start_y*_width + start_x];
- uint16_t * pfbPixel;
- int screen_y = start_y;
- int screen_x;
-
- // Clear above character
- while (screen_y < origin_y) {
- pfbPixel = pfbPixel_row;
- // only output if this line is within the clipping region.
- if ((screen_y >= _displayclipy1) && (screen_y < _displayclipy2)) {
- for (screen_x = start_x; screen_x <= end_x; screen_x++) {
- if (screen_x >= _displayclipx1) {
- *pfbPixel = textbgcolor;
- }
- pfbPixel++;
- }
- }
- screen_y++;
- pfbPixel_row += _width;
- }
-
- // Anti-aliased font
- if (fontbpp>1){
- screen_y = origin_y;
- bitoffset = ((bitoffset + 7) & (-8)); // byte-boundary
- uint32_t xp = 0;
- int glyphend_x = origin_x+width;
- while (linecount) {
- pfbPixel = pfbPixel_row;
- screen_x = start_x;
- while(screen_x<=end_x) {
- // XXX: I'm sure clipping could be done way more efficiently than just chekcing every single pixel, but let's just get this going
- if ((screen_x >= _displayclipx1) && (screen_x < _displayclipx2) && (screen_y >= _displayclipy1) && (screen_y < _displayclipy2)) {
- // Clear before or after pixel
- if ((screen_x<origin_x) || (screen_x>=glyphend_x)){
- *pfbPixel = textbgcolor;
- }
- // Draw alpha-blended character
- else{
- uint8_t alpha = fetchpixel(data, bitoffset, xp);
- *pfbPixel = alphaBlendRGB565Premultiplied( textcolorPrexpanded, textbgcolorPrexpanded, (uint8_t)(alpha * fontalphamx) );
- bitoffset += fontbpp;
- xp++;
- }
- } // clip
- screen_x++;
- pfbPixel++;
- }
- pfbPixel_row += _width;
- screen_y++;
- linecount--;
- }
-
- } // anti-aliased
-
- // 1bpp solid font
- else{
-
- // Now lets process each of the data lines (draw character)
- screen_y = origin_y;
- while (linecount > 0) {
- //Serial.printf(" linecount = %d\n", linecount);
- uint32_t b = fetchbit(data, bitoffset++);
- uint32_t n;
- if (b == 0) {
- //Serial.println("Single");
- n = 1;
- } else {
- //Serial.println("Multi");
- n = fetchbits_unsigned(data, bitoffset, 3) + 2;
- bitoffset += 3;
- }
- uint32_t bitoffset_row_start = bitoffset;
- while (n--) {
- pfbPixel = pfbPixel_row;
-
- // Clear to left
- if ((screen_y >= _displayclipy1) && (screen_y < _displayclipy2)) {
- bitoffset = bitoffset_row_start; // we will work through these bits maybe multiple times
- for (screen_x = start_x; screen_x < origin_x; screen_x++) {
- if (screen_x >= _displayclipx1) {
- *pfbPixel = textbgcolor;
- } // make sure not clipped
- pfbPixel++;
- }
- }
-
- // Pixel bits
- screen_x = origin_x;
- uint32_t x = 0;
- do {
- uint32_t xsize = width - x;
- if (xsize > 32) xsize = 32;
- uint32_t bits = fetchbits_unsigned(data, bitoffset, xsize);
- uint32_t bit_mask = 1 << (xsize-1);
- //Serial.printf(" %d %d %x %x\n", x, xsize, bits, bit_mask);
- if ((screen_y >= _displayclipy1) && (screen_y < _displayclipy2)) {
- while (bit_mask && (screen_x <= end_x)) {
- if ((screen_x >= _displayclipx1) && (screen_x < _displayclipx2)) {
- *pfbPixel = (bits & bit_mask) ? textcolor : textbgcolor;
- }
- pfbPixel++;
- bit_mask = bit_mask >> 1;
- screen_x++; // increment our pixel position.
- }
- }
- bitoffset += xsize;
- x += xsize;
- } while (x < width);
-
- // Clear to right
- if ((screen_y >= _displayclipy1) && (screen_y < _displayclipy2)) {
- // output bg color and right hand side
- while (screen_x++ <= end_x) {
- *pfbPixel++ = textbgcolor;
- }
- }
- screen_y++;
- pfbPixel_row += _width;
- linecount--;
- }
- }
-
- } // 1bpp
-
- // clear below character
- while (screen_y++ <= end_y) {
- if ((screen_y >= _displayclipy1) && (screen_y < _displayclipy2)) {
- pfbPixel = pfbPixel_row;
- for (screen_x = start_x; screen_x <= end_x; screen_x++) {
- if (screen_x >= _displayclipx1) {
- *pfbPixel = textbgcolor;
- }
- pfbPixel++;
- }
- }
- pfbPixel_row += _width;
- }
-
- } else
- #endif
- {
-
- beginSPITransaction();
- //Serial.printf("SetAddr %d %d %d %d\n", start_x_min, start_y_min, end_x, end_y);
- // output rectangle we are updating... We have already clipped end_x/y, but not yet start_x/y
- setAddr( start_x, start_y_min, end_x, end_y);
- writecommand(ST7735_RAMWR);
- int screen_y = start_y_min;
- int screen_x;
-
- // Clear above character
- while (screen_y < origin_y) {
- for (screen_x = start_x_min; screen_x <= end_x; screen_x++) {
- writedata16(textbgcolor);
- }
- screen_y++;
- }
-
- // Anti-aliased font
- if (fontbpp>1){
- screen_y = origin_y;
- bitoffset = ((bitoffset + 7) & (-8)); // byte-boundary
- int glyphend_x = origin_x+width;
- uint32_t xp = 0;
- while (linecount) {
- screen_x = start_x;
- while(screen_x<=end_x) {
- // XXX: I'm sure clipping could be done way more efficiently than just chekcing every single pixel, but let's just get this going
- if ((screen_x >= _displayclipx1) && (screen_x < _displayclipx2) && (screen_y >= _displayclipy1) && (screen_y < _displayclipy2)) {
- // Clear before or after pixel
- if ((screen_x<origin_x) || (screen_x>=glyphend_x)){
- writedata16(textbgcolor);
- }
- // Draw alpha-blended character
- else{
- uint8_t alpha = fetchpixel(data, bitoffset, xp);
- writedata16( alphaBlendRGB565Premultiplied( textcolorPrexpanded, textbgcolorPrexpanded, (uint8_t)(alpha * fontalphamx) ) );
- bitoffset += fontbpp;
- xp++;
- }
- } // clip
- screen_x++;
- }
- screen_y++;
- linecount--;
- }
-
- } // anti-aliased
-
- // 1bpp
- else{
-
- // Now lets process each of the data lines.
- screen_y = origin_y;
- while (linecount > 0) {
- //Serial.printf(" linecount = %d\n", linecount);
- uint32_t b = fetchbit(data, bitoffset++);
- uint32_t n;
- if (b == 0) {
- //Serial.println(" Single");
- n = 1;
- } else {
- //Serial.println(" Multi");
- n = fetchbits_unsigned(data, bitoffset, 3) + 2;
- bitoffset += 3;
- }
- uint32_t bitoffset_row_start = bitoffset;
- while (n--) {
- // do some clipping here.
- bitoffset = bitoffset_row_start; // we will work through these bits maybe multiple times
- // We need to handle case where some of the bits may not be visible, but we still need to
- // read through them
- //Serial.printf("y:%d %d %d %d %d\n", screen_y, start_x, origin_x, _displayclipx1, _displayclipx2);
- if ((screen_y >= _displayclipy1) && (screen_y < _displayclipy2)) {
- for (screen_x = start_x; screen_x < origin_x; screen_x++) {
- if ((screen_x >= _displayclipx1) && (screen_x < _displayclipx2)) {
- //Serial.write('-');
- writedata16(textbgcolor);
- }
- }
- }
- uint32_t x = 0;
- screen_x = origin_x;
- do {
- uint32_t xsize = width - x;
- if (xsize > 32) xsize = 32;
- uint32_t bits = fetchbits_unsigned(data, bitoffset, xsize);
- uint32_t bit_mask = 1 << (xsize-1);
- //Serial.printf(" %d %d %x %x - ", x, xsize, bits, bit_mask);
- if ((screen_y >= _displayclipy1) && (screen_y < _displayclipy2)) {
- while (bit_mask) {
- if ((screen_x >= _displayclipx1) && (screen_x < _displayclipx2)) {
- writedata16((bits & bit_mask) ? textcolor : textbgcolor);
- //Serial.write((bits & bit_mask) ? '*' : '.');
- }
- bit_mask = bit_mask >> 1;
- screen_x++ ; // Current actual screen X
- }
- //Serial.println();
- bitoffset += xsize;
- }
- x += xsize;
- } while (x < width) ;
- if ((screen_y >= _displayclipy1) && (screen_y < _displayclipy2)) {
- // output bg color and right hand side
- while (screen_x++ <= end_x) {
- writedata16(textbgcolor);
- //Serial.write('+');
- }
- //Serial.println();
- }
- screen_y++;
- linecount--;
- }
- }
- } // 1bpp
-
- // clear below character - note reusing xcreen_x for this
- screen_x = (end_y + 1 - screen_y) * (end_x + 1 - start_x_min); // How many bytes we need to still output
- //Serial.printf("Clear Below: %d\n", screen_x);
- while (screen_x-- > 1) {
- writedata16(textbgcolor);
- }
- writedata16_last(textbgcolor);
- endSPITransaction();
- }
-
- }
- // Increment to setup for the next character.
- cursor_x += delta;
-
- }
-
- //strPixelLen - gets pixel length of given ASCII string
- int16_t ST7735_t3::strPixelLen(const char * str)
- {
- // //Serial.printf("strPixelLen %s\n", str);
- if (!str) return(0);
- if (gfxFont)
- {
- // BUGBUG:: just use the other function for now... May do this for all of them...
- int16_t x, y;
- uint16_t w, h;
- getTextBounds(str, cursor_x, cursor_y, &x, &y, &w, &h);
- return w;
- }
-
- uint16_t len=0, maxlen=0;
- while (*str)
- {
- if (*str=='\n')
- {
- if ( len > maxlen )
- {
- maxlen=len;
- len=0;
- }
- }
- else
- {
- if (!font)
- {
- len+=textsize_x*6;
- }
- else
- {
-
- uint32_t bitoffset;
- const uint8_t *data;
- uint16_t c = *str;
-
- // //Serial.printf("char %c(%d)\n", c,c);
-
- if (c >= font->index1_first && c <= font->index1_last) {
- bitoffset = c - font->index1_first;
- bitoffset *= font->bits_index;
- } else if (c >= font->index2_first && c <= font->index2_last) {
- bitoffset = c - font->index2_first + font->index1_last - font->index1_first + 1;
- bitoffset *= font->bits_index;
- } else if (font->unicode) {
- continue;
- } else {
- continue;
- }
- //Serial.printf(" index = %d\n", fetchbits_unsigned(font->index, bitoffset, font->bits_index));
- data = font->data + fetchbits_unsigned(font->index, bitoffset, font->bits_index);
-
- uint32_t encoding = fetchbits_unsigned(data, 0, 3);
- if (encoding != 0) continue;
- // uint32_t width = fetchbits_unsigned(data, 3, font->bits_screenWidth);
- // //Serial.printf(" width = %d\n", width);
- bitoffset = font->bits_width + 3;
- bitoffset += font->bits_height;
-
- // int32_t xoffset = fetchbits_signed(data, bitoffset, font->bits_xoffset);
- // //Serial.printf(" xoffset = %d\n", xoffset);
- bitoffset += font->bits_xoffset;
- bitoffset += font->bits_yoffset;
-
- uint32_t delta = fetchbits_unsigned(data, bitoffset, font->bits_delta);
- bitoffset += font->bits_delta;
- // //Serial.printf(" delta = %d\n", delta);
-
- len += delta;//+width-xoffset;
- // //Serial.printf(" len = %d\n", len);
- }
-
- if ( len > maxlen )
- {
- maxlen=len;
- // //Serial.printf(" maxlen = %d\n", maxlen);
- }
- }
- str++;
- }
- // //Serial.printf("Return maxlen = %d\n", maxlen);
- return( maxlen );
- }
-
- void ST7735_t3::charBounds(char c, int16_t *x, int16_t *y,
- int16_t *minx, int16_t *miny, int16_t *maxx, int16_t *maxy) {
-
- // BUGBUG:: Not handling offset/clip
- if (font) {
- if(c == '\n') { // Newline?
- *x = 0; // Reset x to zero, advance y by one line
- *y += font->line_space;
- } else if(c != '\r') { // Not a carriage return; is normal char
- uint32_t bitoffset;
- const uint8_t *data;
- if (c >= font->index1_first && c <= font->index1_last) {
- bitoffset = c - font->index1_first;
- bitoffset *= font->bits_index;
- } else if (c >= font->index2_first && c <= font->index2_last) {
- bitoffset = c - font->index2_first + font->index1_last - font->index1_first + 1;
- bitoffset *= font->bits_index;
- } else if (font->unicode) {
- return; // TODO: implement sparse unicode
- } else {
- return;
- }
- //Serial.printf(" index = %d\n", fetchbits_unsigned(font->index, bitoffset, font->bits_index));
- data = font->data + fetchbits_unsigned(font->index, bitoffset, font->bits_index);
-
- uint32_t encoding = fetchbits_unsigned(data, 0, 3);
- if (encoding != 0) return;
- uint32_t width = fetchbits_unsigned(data, 3, font->bits_width);
- bitoffset = font->bits_width + 3;
- uint32_t height = fetchbits_unsigned(data, bitoffset, font->bits_height);
- bitoffset += font->bits_height;
- //Serial.printf(" size = %d,%d\n", width, height);
- //Serial.printf(" line space = %d\n", font->line_space);
-
- int32_t xoffset = fetchbits_signed(data, bitoffset, font->bits_xoffset);
- bitoffset += font->bits_xoffset;
- int32_t yoffset = fetchbits_signed(data, bitoffset, font->bits_yoffset);
- bitoffset += font->bits_yoffset;
-
- uint32_t delta = fetchbits_unsigned(data, bitoffset, font->bits_delta);
- bitoffset += font->bits_delta;
-
- int16_t
- x1 = *x + xoffset,
- y1 = *y + yoffset,
- x2 = x1 + width,
- y2 = y1 + height;
-
- if(wrap && (x2 > _width)) {
- *x = 0; // Reset x to zero, advance y by one line
- *y += font->line_space;
- x1 = *x + xoffset,
- y1 = *y + yoffset,
- x2 = x1 + width,
- y2 = y1 + height;
- }
- if(x1 < *minx) *minx = x1;
- if(y1 < *miny) *miny = y1;
- if(x2 > *maxx) *maxx = x2;
- if(y2 > *maxy) *maxy = y2;
- *x += delta; // ? guessing here...
- }
- }
-
- else if(gfxFont) {
-
- if(c == '\n') { // Newline?
- *x = 0; // Reset x to zero, advance y by one line
- *y += textsize_y * gfxFont->yAdvance;
- } else if(c != '\r') { // Not a carriage return; is normal char
- uint8_t first = gfxFont->first,
- last = gfxFont->last;
- if((c >= first) && (c <= last)) { // Char present in this font?
- GFXglyph *glyph = gfxFont->glyph + (c - first);
- uint8_t gw = glyph->width,
- gh = glyph->height,
- xa = glyph->xAdvance;
- int8_t xo = glyph->xOffset,
- yo = glyph->yOffset + gfxFont->yAdvance/2;
- if(wrap && ((*x+(((int16_t)xo+gw)*textsize_x)) > _width)) {
- *x = 0; // Reset x to zero, advance y by one line
- *y += textsize_y * gfxFont->yAdvance;
- }
- int16_t tsx = (int16_t)textsize_x,
- tsy = (int16_t)textsize_y,
- x1 = *x + xo * tsx,
- y1 = *y + yo * tsy,
- x2 = x1 + gw * tsx - 1,
- y2 = y1 + gh * tsy - 1;
- if(x1 < *minx) *minx = x1;
- if(y1 < *miny) *miny = y1;
- if(x2 > *maxx) *maxx = x2;
- if(y2 > *maxy) *maxy = y2;
- *x += xa * tsx;
- }
- }
-
- } else { // Default font
-
- if(c == '\n') { // Newline?
- *x = 0; // Reset x to zero,
- *y += textsize_y * 8; // advance y one line
- // min/max x/y unchaged -- that waits for next 'normal' character
- } else if(c != '\r') { // Normal char; ignore carriage returns
- if(wrap && ((*x + textsize_x * 6) > _width)) { // Off right?
- *x = 0; // Reset x to zero,
- *y += textsize_y * 8; // advance y one line
- }
- int x2 = *x + textsize_x * 6 - 1, // Lower-right pixel of char
- y2 = *y + textsize_y * 8 - 1;
- if(x2 > *maxx) *maxx = x2; // Track max x, y
- if(y2 > *maxy) *maxy = y2;
- if(*x < *minx) *minx = *x; // Track min x, y
- if(*y < *miny) *miny = *y;
- *x += textsize_x * 6; // Advance x one char
- }
- }
- }
-
- // Add in Adafruit versions of text bounds calculations.
- void ST7735_t3::getTextBounds(const uint8_t *buffer, uint16_t len, int16_t x, int16_t y,
- int16_t *x1, int16_t *y1, uint16_t *w, uint16_t *h) {
- *x1 = x;
- *y1 = y;
- *w = *h = 0;
-
- int16_t minx = _width, miny = _height, maxx = -1, maxy = -1;
-
- while(len--)
- charBounds(*buffer++, &x, &y, &minx, &miny, &maxx, &maxy);
-
- if(maxx >= minx) {
- *x1 = minx;
- *w = maxx - minx + 1;
- }
- if(maxy >= miny) {
- *y1 = miny;
- *h = maxy - miny + 1;
- }
- }
- void ST7735_t3::getTextBounds(const char *str, int16_t x, int16_t y,
- int16_t *x1, int16_t *y1, uint16_t *w, uint16_t *h) {
- uint8_t c; // Current character
-
- *x1 = x;
- *y1 = y;
- *w = *h = 0;
-
- int16_t minx = _width, miny = _height, maxx = -1, maxy = -1;
-
- while((c = *str++))
- charBounds(c, &x, &y, &minx, &miny, &maxx, &maxy);
-
- if(maxx >= minx) {
- *x1 = minx;
- *w = maxx - minx + 1;
- }
- if(maxy >= miny) {
- *y1 = miny;
- *h = maxy - miny + 1;
- }
- }
-
- void ST7735_t3::getTextBounds(const String &str, int16_t x, int16_t y,
- int16_t *x1, int16_t *y1, uint16_t *w, uint16_t *h) {
- if (str.length() != 0) {
- getTextBounds(const_cast<char*>(str.c_str()), x, y, x1, y1, w, h);
- }
- }
-
-
-
- void ST7735_t3::drawFontPixel( uint8_t alpha, uint32_t x, uint32_t y ){
- // Adjust alpha based on the number of alpha levels supported by the font (based on bpp)
- // Note: Implemented look-up table for alpha, but made absolutely no difference in speed (T3.6)
- alpha = (uint8_t)(alpha * fontalphamx);
- uint32_t result = ((((textcolorPrexpanded - textbgcolorPrexpanded) * alpha) >> 5) + textbgcolorPrexpanded) & 0b00000111111000001111100000011111;
- Pixel(x,y,(uint16_t)((result >> 16) | result));
- }
-
- void ST7735_t3::drawFontBits(bool opaque, uint32_t bits, uint32_t numbits, int32_t x, int32_t y, uint32_t repeat)
- {
- if (bits == 0) {
- if (opaque) {
- fillRect(x, y, numbits, repeat, textbgcolor);
- }
- } else {
- int32_t x1 = x;
- uint32_t n = numbits;
- int w;
- int bgw;
-
- w = 0;
- bgw = 0;
-
- do {
- n--;
- if (bits & (1 << n)) {
- if (bgw>0) {
- if (opaque) {
- fillRect(x1 - bgw, y, bgw, repeat, textbgcolor);
- }
- bgw=0;
- }
- w++;
- } else {
- if (w>0) {
- fillRect(x1 - w, y, w, repeat, textcolor);
- w = 0;
- }
- bgw++;
- }
- x1++;
- } while (n > 0);
-
- if (w > 0) {
- fillRect(x1 - w, y, w, repeat, textcolor);
- }
-
- if (bgw > 0) {
- if (opaque) {
- fillRect(x1 - bgw, y, bgw, repeat, textbgcolor);
- }
- }
- }
- }
-
- void ST7735_t3::drawGFXFontChar(unsigned int c) {
- // Lets do Adafruit GFX character output here as well
- if(c == '\r') return;
-
- // Some quick and dirty tests to see if we can
- uint8_t first = gfxFont->first;
- if((c < first) || (c > gfxFont->last)) return;
-
- GFXglyph *glyph = gfxFont->glyph + (c - first);
- uint8_t w = glyph->width,
- h = glyph->height;
-
- // wonder if we should look at xo, yo instead?
- if((w == 0 || h == 0) && (c != 32)) return; // Is there an associated bitmap?
-
- int16_t xo = glyph->xOffset; // sic
- int16_t yo = glyph->yOffset + gfxFont->yAdvance/2;
-
- if(wrap && ((cursor_x + textsize_x * (xo + w)) > _width)) {
- cursor_x = 0;
- cursor_y += (int16_t)textsize_y * gfxFont->yAdvance;
- }
-
- // Lets do the work to output the font character
- uint8_t *bitmap = gfxFont->bitmap;
-
- uint16_t bo = glyph->bitmapOffset;
- uint8_t xx, yy, bits = 0, bit = 0;
- //Serial.printf("DGFX_char: %c (%d,%d) : %u %u %u %u %d %d %x %x %d\n", c, cursor_x, cursor_y, w, h,
- // glyph->xAdvance, gfxFont->yAdvance, xo, yo, textcolor, textbgcolor, _use_fbtft);Serial.flush();
-
- if (textcolor == textbgcolor) {
-
- //Serial.printf("DGFXChar: %c %u, %u, wh:%d %d o:%d %d\n", c, cursor_x, cursor_y, w, h, xo, yo);
-
- // NOTE: Adafruit GFX does not support Opaque font output as there
- // are issues with proportionally spaced characters that may overlap
- // So the below is not perfect as we may overwrite a small portion
- // of a letter with the next one, when we blank out...
- // But: I prefer to let each of us decide if the limitations are
- // worth it or not. If Not you still have the option to not
- // Do transparent mode and instead blank out and blink...
- for(yy=0; yy<h; yy++) {
- uint8_t w_left = w;
- xx = 0;
- while (w_left) {
- if(!(bit & 7)) {
- bits = bitmap[bo++];
- }
- // Could try up to 8 bits at time, but start off trying up to 4
- uint8_t xCount;
- if ((w_left >= 8) && ((bits & 0xff) == 0xff)) {
- xCount = 8;
- //Serial.print("8");
- fillRect(cursor_x+(xo+xx)*textsize_x, cursor_y+(yo+yy)*textsize_y,
- xCount * textsize_x, textsize_y, textcolor);
- } else if ((w_left >= 4) && ((bits & 0xf0) == 0xf0)) {
- xCount = 4;
- //Serial.print("4");
- fillRect(cursor_x+(xo+xx)*textsize_x, cursor_y+(yo+yy)*textsize_y,
- xCount * textsize_x, textsize_y, textcolor);
- } else if ((w_left >= 3) && ((bits & 0xe0) == 0xe0)) {
- //Serial.print("3");
- xCount = 3;
- fillRect(cursor_x+(xo+xx)*textsize_x, cursor_y+(yo+yy)*textsize_y,
- xCount * textsize_x, textsize_y, textcolor);
- } else if ((w_left >= 2) && ((bits & 0xc0) == 0xc0)) {
- //Serial.print("2");
- xCount = 2;
- fillRect(cursor_x+(xo+xx)*textsize_x, cursor_y+(yo+yy)*textsize_y,
- xCount * textsize_x, textsize_y, textcolor);
- } else {
- xCount = 1;
- if(bits & 0x80) {
- if((textsize_x == 1) && (textsize_y == 1)){
- drawPixel(cursor_x+xo+xx, cursor_y+yo+yy, textcolor);
- } else {
- fillRect(cursor_x+(xo+xx)*textsize_x, cursor_y+(yo+yy)*textsize_y,
- textsize_x, textsize_y, textcolor);
- }
- }
- }
- xx += xCount;
- w_left -= xCount;
- bit += xCount;
- bits <<= xCount;
- }
-
- }
- _gfx_last_char_x_write = 0;
- } else {
- // To Do, properly clipping and offsetting...
- // This solid background approach is about 5 time faster
- // Lets calculate bounding rectangle that we will update
- // We need to offset by the origin.
-
- // We are going direct so do some offsets and clipping
- int16_t x_offset_cursor = cursor_x + _originx; // This is where the offseted cursor is.
- int16_t x_start = x_offset_cursor; // I am assuming no negative x offsets.
- int16_t x_end = x_offset_cursor + (glyph->xAdvance * textsize_x);
- if (glyph->xAdvance < (xo + w)) x_end = x_offset_cursor + ((xo + w)* textsize_x); // BUGBUG Overlflows into next char position.
- int16_t x_left_fill = x_offset_cursor + xo * textsize_x;
- int16_t x;
-
- if (xo < 0) {
- // Unusual character that goes back into previous character
- //Serial.printf("GFX Font char XO < 0: %c %d %d %u %u %u\n", c, xo, yo, w, h, glyph->xAdvance );
- x_start += xo * textsize_x;
- x_left_fill = 0; // Don't need to fill anything here...
- }
-
- int16_t y_start = cursor_y + _originy + (_gfxFont_min_yOffset * textsize_y)+ gfxFont->yAdvance*textsize_y/2; // UP to most negative value.
- int16_t y_end = y_start + gfxFont->yAdvance * textsize_y; // how far we will update
- int16_t y = y_start;
- //int8_t y_top_fill = (yo - _gfxFont_min_yOffset) * textsize_y; // both negative like -10 - -16 = 6...
- int8_t y_top_fill = (yo - gfxFont->yAdvance/2 - _gfxFont_min_yOffset) * textsize_y;
-
- // See if anything is within clip rectangle, if not bail
- if((x_start >= _displayclipx2) || // Clip right
- (y_start >= _displayclipy2) || // Clip bottom
- (x_end < _displayclipx1) || // Clip left
- (y_end < _displayclipy1)) // Clip top
- {
- // But remember to first update the cursor position
- cursor_x += glyph->xAdvance * (int16_t)textsize_x;
- return;
- }
-
- // If our y_end > _displayclipy2 set it to _displayclipy2 as to not have to test both Likewise X
- if (y_end > _displayclipy2) y_end = _displayclipy2;
- if (x_end > _displayclipx2) x_end = _displayclipx2;
-
- // If we get here and
- if (_gfx_last_cursor_y != (cursor_y + _originy)) _gfx_last_char_x_write = 0;
-
- #ifdef ENABLE_ST77XX_FRAMEBUFFER
- if (_use_fbtft) {
- // lets try to output the values directly...
- uint16_t * pfbPixel_row = &_pfbtft[ y_start *_width + x_start];
- uint16_t * pfbPixel;
- // First lets fill in the top parts above the actual rectangle...
- while (y_top_fill--) {
- pfbPixel = pfbPixel_row;
- if ( (y >= _displayclipy1) && (y < _displayclipy2)) {
- for (int16_t xx = x_start; xx < x_end; xx++) {
- if ((xx >= _displayclipx1) && (xx >= x_offset_cursor)) {
- if ((xx >= _gfx_last_char_x_write) || (*pfbPixel != _gfx_last_char_textcolor))
- *pfbPixel = textbgcolor;
- }
- pfbPixel++;
- }
- }
- pfbPixel_row += _width;
- y++;
- }
- // Now lets output all of the pixels for each of the rows..
- for(yy=0; (yy<h) && (y < _displayclipy2); yy++) {
- uint16_t bo_save = bo;
- uint8_t bit_save = bit;
- uint8_t bits_save = bits;
- for (uint8_t yts = 0; (yts < textsize_y) && (y < _displayclipy2); yts++) {
- pfbPixel = pfbPixel_row;
- // need to repeat the stuff for each row...
- bo = bo_save;
- bit = bit_save;
- bits = bits_save;
- x = x_start;
- if (y >= _displayclipy1) {
- while (x < x_left_fill) {
- if ( (x >= _displayclipx1) && (x < _displayclipx2)) {
- if ((x >= _gfx_last_char_x_write) || (*pfbPixel != _gfx_last_char_textcolor))
- *pfbPixel = textbgcolor;
- }
- pfbPixel++;
- x++;
-
- }
- for(xx=0; xx<w; xx++) {
- if(!(bit++ & 7)) {
- bits = bitmap[bo++];
- }
- for (uint8_t xts = 0; xts < textsize_x; xts++) {
- if ( (x >= _displayclipx1) && (x < _displayclipx2)) {
- if (bits & 0x80)
- *pfbPixel = textcolor;
- else if (x >= x_offset_cursor) {
- if ((x >= _gfx_last_char_x_write) || (*pfbPixel != _gfx_last_char_textcolor))
- *pfbPixel = textbgcolor;
- }
- }
- pfbPixel++;
- x++; // remember our logical position...
- }
- bits <<= 1;
- }
- // Fill in any additional bg colors to right of our output
- while (x++ < x_end) {
- if (x >= _displayclipx1) {
- *pfbPixel = textbgcolor;
- }
- pfbPixel++;
- }
- }
- y++; // remember which row we just output
- pfbPixel_row += _width;
- }
- }
- // And output any more rows below us...
- while (y < y_end) {
- if (y >= _displayclipy1) {
- pfbPixel = pfbPixel_row;
- for (int16_t xx = x_start; xx < x_end; xx++) {
- if ((xx >= _displayclipx1) && (xx >= x_offset_cursor)) {
- if ((xx >= _gfx_last_char_x_write) || (*pfbPixel != _gfx_last_char_textcolor))
- *pfbPixel = textbgcolor;
- }
- pfbPixel++;
- }
- }
- pfbPixel_row += _width;
- y++;
- }
-
- } else
- #endif
- {
- // lets try to output text in one output rectangle
- //Serial.printf(" SPI (%d %d) (%d %d)\n", x_start, y_start, x_end, y_end);Serial.flush();
- // compute the actual region we will output given
- beginSPITransaction();
-
- setAddr((x_start >= _displayclipx1) ? x_start : _displayclipx1,
- (y_start >= _displayclipy1) ? y_start : _displayclipy1,
- x_end - 1, y_end - 1);
- writecommand(ST7735_RAMWR);
- //Serial.printf("SetAddr: %u %u %u %u\n", (x_start >= _displayclipx1) ? x_start : _displayclipx1,
- // (y_start >= _displayclipy1) ? y_start : _displayclipy1,
- // x_end - 1, y_end - 1);
- // First lets fill in the top parts above the actual rectangle...
- //Serial.printf(" y_top_fill %d x_left_fill %d\n", y_top_fill, x_left_fill);
- while (y_top_fill--) {
- if ( (y >= _displayclipy1) && (y < _displayclipy2)) {
- for (int16_t xx = x_start; xx < x_end; xx++) {
- if (xx >= _displayclipx1) {
- writedata16(gfxFontLastCharPosFG(xx,y)? _gfx_last_char_textcolor : (xx < x_offset_cursor)? _gfx_last_char_textbgcolor : textbgcolor);
- }
- }
- }
- y++;
- }
- //Serial.println(" After top fill"); Serial.flush();
- // Now lets output all of the pixels for each of the rows..
- for(yy=0; (yy<h) && (y < _displayclipy2); yy++) {
- uint16_t bo_save = bo;
- uint8_t bit_save = bit;
- uint8_t bits_save = bits;
- for (uint8_t yts = 0; (yts < textsize_y) && (y < _displayclipy2); yts++) {
- // need to repeat the stuff for each row...
- bo = bo_save;
- bit = bit_save;
- bits = bits_save;
- x = x_start;
- if (y >= _displayclipy1) {
- while (x < x_left_fill) {
- if ( (x >= _displayclipx1) && (x < _displayclipx2) ) {
- // Don't need to check if we are in previous char as in this case x_left_fill is set to 0...
- writedata16(gfxFontLastCharPosFG(x,y)? _gfx_last_char_textcolor : textbgcolor);
- }
- x++;
- }
- for(xx=0; xx<w; xx++) {
- if(!(bit++ & 7)) {
- bits = bitmap[bo++];
- }
- for (uint8_t xts = 0; xts < textsize_x; xts++) {
- if ( (x >= _displayclipx1) && (x < _displayclipx2)) {
- if (bits & 0x80)
- writedata16(textcolor);
- else
- writedata16(gfxFontLastCharPosFG(x,y)? _gfx_last_char_textcolor : (x < x_offset_cursor)? _gfx_last_char_textbgcolor : textbgcolor);
- }
- x++; // remember our logical position...
- }
- bits <<= 1;
- }
- // Fill in any additional bg colors to right of our output
- while (x < x_end) {
- if (x >= _displayclipx1) {
- writedata16(gfxFontLastCharPosFG(x,y)? _gfx_last_char_textcolor : (x < x_offset_cursor)? _gfx_last_char_textbgcolor : textbgcolor);
- }
- x++;
- }
- }
- y++; // remember which row we just output
- }
- }
- // And output any more rows below us...
- //Serial.println(" Bottom fill"); Serial.flush();
- while (y < y_end) {
- if (y >= _displayclipy1) {
- for (int16_t xx = x_start; xx < x_end; xx++) {
- if (xx >= _displayclipx1 ) {
- writedata16(gfxFontLastCharPosFG(xx,y)? _gfx_last_char_textcolor : (xx < x_offset_cursor)? _gfx_last_char_textbgcolor : textbgcolor);
- }
- }
- }
- y++;
- }
- writecommand_last(ST7735_NOP);
- endSPITransaction();
- }
- // Save away info about this last char
- _gfx_c_last = c;
- _gfx_last_cursor_x = cursor_x + _originx;
- _gfx_last_cursor_y = cursor_y + _originy;
- _gfx_last_char_x_write = x_end;
- _gfx_last_char_textcolor = textcolor;
- _gfx_last_char_textbgcolor = textbgcolor;
- }
-
- cursor_x += glyph->xAdvance * (int16_t)textsize_x;
- }
-
- // Some fonts overlap characters if we detect that the previous
- // character wrote out more width than they advanced in X direction
- // we may want to know if the last character output a FG or BG at a position.
- // Opaque font chracter overlap?
- // unsigned int _gfx_c_last;
- // int16_t _gfx_last_cursor_x, _gfx_last_cursor_y;
- // int16_t _gfx_last_x_overlap = 0;
-
- bool ST7735_t3::gfxFontLastCharPosFG(int16_t x, int16_t y) {
- GFXglyph *glyph = gfxFont->glyph + (_gfx_c_last - gfxFont->first);
-
- uint8_t w = glyph->width,
- h = glyph->height;
-
-
- int16_t xo = glyph->xOffset; // sic
- int16_t yo = glyph->yOffset + gfxFont->yAdvance/2;
- if (x >= _gfx_last_char_x_write) return false; // we did not update here...
- if (y < (_gfx_last_cursor_y + (yo*textsize_y))) return false; // above
- if (y >= (_gfx_last_cursor_y + (yo+h)*textsize_y)) return false; // below
-
-
- // Lets compute which Row this y is in the bitmap
- int16_t y_bitmap = (y - ((_gfx_last_cursor_y + (yo*textsize_y))) + textsize_y - 1) / textsize_y;
- int16_t x_bitmap = (x - ((_gfx_last_cursor_x + (xo*textsize_x))) + textsize_x - 1) / textsize_x;
- uint16_t pixel_bit_offset = y_bitmap * w + x_bitmap;
-
- return ((gfxFont->bitmap[glyph->bitmapOffset + (pixel_bit_offset >> 3)]) & (0x80 >> (pixel_bit_offset & 0x7)));
- }
-
-
-
- #ifdef ENABLE_ST77XX_FRAMEBUFFER
- void ST7735_t3::dmaInterrupt(void) {
- if (_dmaActiveDisplay[0]) {
- _dmaActiveDisplay[0]->process_dma_interrupt();
- }
- }
- void ST7735_t3::dmaInterrupt1(void) {
- if (_dmaActiveDisplay[1]) {
- _dmaActiveDisplay[1]->process_dma_interrupt();
- }
- }
- void ST7735_t3::dmaInterrupt2(void) {
- if (_dmaActiveDisplay[2]) {
- _dmaActiveDisplay[2]->process_dma_interrupt();
- }
- }
-
- //=============================================================================
- // Frame buffer support.
- //=============================================================================
- #ifdef ENABLE_ST77XX_FRAMEBUFFER
- #ifdef DEBUG_ASYNC_UPDATE
- extern void dumpDMA_TCD(DMABaseClass *dmabc);
- #endif
-
- void ST7735_t3::process_dma_interrupt(void) {
- #ifdef DEBUG_ASYNC_LEDS
- digitalWriteFast(DEBUG_PIN_2, HIGH);
- #endif
- // Serial.println(" ST7735_t3::process_dma_interrupt");
- #if defined(__MK66FX1M0__)
- // T3.6
- _dma_frame_count++;
- _dmatx.clearInterrupt();
-
- // See if we are in continuous mode or not..
- if ((_dma_state & ST77XX_DMA_CONT) == 0) {
- // We are in single refresh mode or the user has called cancel so
- // Lets try to release the CS pin
- while (((_pkinetisk_spi->SR) & (15 << 12)) > _fifo_full_test) ; // wait if FIFO full
- writecommand_last(ST7735_NOP);
- endSPITransaction();
- _dma_state &= ~ST77XX_DMA_ACTIVE;
- _dmaActiveDisplay[_spi_num] = 0; // We don't have a display active any more...
-
- }
- #elif defined(__IMXRT1062__) // Teensy 4.x
- // T4
- bool still_more_dma = true;
- _dma_sub_frame_count++;
- #if defined(DEBUG_ASYNC_UPDATE)
- Serial.print(".");
- #endif
- if (_dma_sub_frame_count == _dma_cnt_sub_frames_per_frame) {
- #ifdef DEBUG_ASYNC_LEDS
- digitalWriteFast(DEBUG_PIN_3, HIGH);
- #endif
- #if defined(DEBUG_ASYNC_UPDATE)
- Serial.println("*");
- #endif
- // We completed a frame.
- _dma_frame_count++;
- // See if we are logically done
- if (_dma_state & ST77XX_DMA_FINISH) {
- //Serial.println("$");
- still_more_dma = false;
-
- // We are in single refresh mode or the user has called cancel so
- // Lets try to release the CS pin
- // Lets wait until FIFO is not empty
- //Serial.printf("Before FSR wait: %x %x\n", _pimxrt_spi->FSR, _pimxrt_spi->SR);
- while (_pimxrt_spi->FSR & 0x1f) ; // wait until this one is complete
-
- //Serial.printf("Before SR busy wait: %x\n", _pimxrt_spi->SR);
- while (_pimxrt_spi->SR & LPSPI_SR_MBF) ; // wait until this one is complete
-
- _dma_data[_spi_num]._dmatx.clearComplete();
- //Serial.println("Restore FCR");
- _pimxrt_spi->FCR = LPSPI_FCR_TXWATER(15); // _spi_fcr_save; // restore the FSR status...
- _pimxrt_spi->DER = 0; // DMA no longer doing TX (or RX)
-
- _pimxrt_spi->CR = LPSPI_CR_MEN | LPSPI_CR_RRF | LPSPI_CR_RTF; // actually clear both...
- _pimxrt_spi->SR = 0x3f00; // clear out all of the other status...
-
-
- // maybeUpdateTCR(_tcr_dc_assert | LPSPI_TCR_FRAMESZ(7)); // output Command with 8 bits
- // Serial.printf("Output NOP (SR %x CR %x FSR %x FCR %x %x TCR:%x)\n", _pimxrt_spi->SR, _pimxrt_spi->CR, _pimxrt_spi->FSR,
- // _pimxrt_spi->FCR, _spi_fcr_save, _pimxrt_spi->TCR);
- _pending_rx_count = 0; // Make sure count is zero
- // writecommand_last(ST7735_NOP);
-
- // Serial.println("Do End transaction");
- endSPITransaction();
- _dma_state &= ~(ST77XX_DMA_ACTIVE | ST77XX_DMA_FINISH);
- _dmaActiveDisplay[_spi_num] = 0; // We don't have a display active any more...
-
- // Serial.println("After End transaction");
- #if defined(DEBUG_ASYNC_UPDATE)
- Serial.println("$");
- #endif
- }
- _dma_sub_frame_count = 0;
- #ifdef DEBUG_ASYNC_LEDS
- digitalWriteFast(DEBUG_PIN_3, LOW);
- #endif
- }
-
- if (still_more_dma) {
- // we are still in a sub-frame so we need to copy memory down...
- if (_dma_sub_frame_count == (_dma_cnt_sub_frames_per_frame-2)) {
- if ((_dma_state & ST77XX_DMA_CONT) == 0) {
- if (_dma_sub_frame_count & 1) _dma_data[_spi_num]._dmasettings[0].disableOnCompletion();
- else _dma_data[_spi_num]._dmasettings[1].disableOnCompletion();
- #if defined(DEBUG_ASYNC_UPDATE)
- Serial.println("!");
- #endif
- _dma_state |= ST77XX_DMA_FINISH; // let system know we set the finished state
-
- }
- }
- if (_dma_sub_frame_count & 1) {
- memcpy(_dma_data[_spi_num]._dma_buffer1, &_pfbtft[_dma_pixel_index], _dma_buffer_size*2);
- } else {
- memcpy(_dma_data[_spi_num]._dma_buffer2, &_pfbtft[_dma_pixel_index], _dma_buffer_size*2);
- }
- _dma_pixel_index += _dma_buffer_size;
- if (_dma_pixel_index >= (_count_pixels))
- _dma_pixel_index = 0; // we will wrap around
- }
- _dma_data[_spi_num]._dmatx.clearInterrupt();
- _dma_data[_spi_num]._dmatx.clearComplete();
- asm("dsb");
- #else
- //--------------------------------------------------------------------
- // T3.5...
- _dmarx.clearInterrupt();
- _dmatx.clearComplete();
- _dmarx.clearComplete();
-
- if (!_dma_count_remaining && !(_dma_state & ST77XX_DMA_CONT)) {
- // The DMA transfers are done.
- _dma_frame_count++;
- #ifdef DEBUG_ASYNC_LEDS
- digitalWriteFast(DEBUG_PIN_3, HIGH);
- #endif
-
- _pkinetisk_spi->RSER = 0;
- //_pkinetisk_spi->MCR = SPI_MCR_MSTR | SPI_MCR_CLR_RXF | SPI_MCR_PCSIS(0x1F); // clear out the queue
- _pkinetisk_spi->SR = 0xFF0F0000;
- _pkinetisk_spi->CTAR0 &= ~(SPI_CTAR_FMSZ(8)); // Hack restore back to 8 bits
-
- writecommand_last(ST7735_NOP);
- endSPITransaction();
- _dma_state &= ~ST77XX_DMA_ACTIVE;
- _dmaActiveDisplay[_spi_num] = 0; // We don't have a display active any more...
- #ifdef DEBUG_ASYNC_LEDS
- digitalWriteFast(DEBUG_PIN_3, LOW);
- #endif
-
- } else {
- uint16_t w;
- if (_dma_count_remaining) { // Still part of one frome.
- _dma_count_remaining -= _dma_write_size_words;
- w = *((uint16_t*)_dmatx.TCD->SADDR);
- _dmatx.TCD->SADDR = (volatile uint8_t*)(_dmatx.TCD->SADDR) + 2;
- } else { // start a new frame
- _dma_frame_count++;
- _dmatx.sourceBuffer(&_pfbtft[1], (_dma_write_size_words-1)*2);
- _dmatx.TCD->SLAST = 0; // Finish with it pointing to next location
- w = _pfbtft[0];
- _dma_count_remaining = _count_pixels - _dma_write_size_words; // how much more to transfer?
- }
- #ifdef DEBUG_ASYNC_UPDATE
- // dumpDMA_TCD(&_dmatx);
- // dumpDMA_TCD(&_dmarx);
- #endif
- _pkinetisk_spi->PUSHR = (w | SPI_PUSHR_CTAS(0) | SPI_PUSHR_CONT);
- _dmarx.enable();
- _dmatx.enable();
- }
-
- #endif
- #ifdef DEBUG_ASYNC_LEDS
- digitalWriteFast(DEBUG_PIN_2, LOW);
- #endif
- }
-
- //=======================================================================
- // Add optinal support for using frame buffer to speed up complex outputs
- //=======================================================================
- void ST7735_t3::setFrameBuffer(uint16_t *frame_buffer)
- {
- _pfbtft = frame_buffer;
- // we may not know the size of it, if called before init.
- /* if (_pfbtft != NULL) {
- memset(_pfbtft, 0, _screenWidth*_screenHeight*2);
- } */
- }
-
- uint8_t ST7735_t3::useFrameBuffer(boolean b) // use the frame buffer? First call will allocate
- {
- if (b) {
- // First see if we need to allocate buffer
- _count_pixels = _width * _height; // We may have called setFrameBuffer before we know with and height...
- if (_pfbtft == NULL) {
- // Hack to start frame buffer on 32 byte boundary
- // Note: If called before init maybe larger than we need
- _we_allocated_buffer = (uint16_t *)malloc(_count_pixels*2+32);
- if (_we_allocated_buffer == NULL)
- return 0; // failed
- _pfbtft = (uint16_t*) (((uintptr_t)_we_allocated_buffer + 32) & ~ ((uintptr_t) (31)));
- memset(_pfbtft, 0, _count_pixels*2);
- }
- _use_fbtft = 1;
- } else
- _use_fbtft = 0;
-
- return _use_fbtft;
- }
-
- void ST7735_t3::freeFrameBuffer(void) // explicit call to release the buffer
- {
- if (_we_allocated_buffer) {
- free(_we_allocated_buffer);
- _pfbtft = NULL;
- _use_fbtft = 0; // make sure the use is turned off
- _we_allocated_buffer = NULL;
- }
- }
- void ST7735_t3::updateScreen(void) // call to say update the screen now.
- {
- // Not sure if better here to check flag or check existence of buffer.
- // Will go by buffer as maybe can do interesting things?
- if (_use_fbtft) {
- beginSPITransaction();
- // Doing full window.
- setAddr(0, 0, _width-1, _height-1);
- writecommand(ST7735_RAMWR);
-
- // BUGBUG doing as one shot. Not sure if should or not or do like
- // main code and break up into transactions...
- uint16_t *pfbtft_end = &_pfbtft[(_count_pixels)-1]; // setup
- uint16_t *pftbft = _pfbtft;
-
- // Quick write out the data;
- while (pftbft < pfbtft_end) {
- writedata16(*pftbft++);
- }
- writedata16_last(*pftbft);
-
- endSPITransaction();
- }
- }
-
- #ifdef DEBUG_ASYNC_UPDATE
- void dumpDMA_TCD(DMABaseClass *dmabc)
- {
- Serial.printf("%x %x:", (uint32_t)dmabc, (uint32_t)dmabc->TCD);
-
- Serial.printf("SA:%x SO:%d AT:%x NB:%x SL:%d DA:%x DO: %d CI:%x DL:%x CS:%x BI:%x\n", (uint32_t)dmabc->TCD->SADDR,
- dmabc->TCD->SOFF, dmabc->TCD->ATTR, dmabc->TCD->NBYTES, dmabc->TCD->SLAST, (uint32_t)dmabc->TCD->DADDR,
- dmabc->TCD->DOFF, dmabc->TCD->CITER, dmabc->TCD->DLASTSGA, dmabc->TCD->CSR, dmabc->TCD->BITER);
- }
- #endif
-
- //==============================================
- #ifdef ENABLE_ST77XX_FRAMEBUFFER
- void ST7735_t3::initDMASettings(void)
- {
- // Serial.printf("initDMASettings called %d\n", _dma_state);
- if (_dma_state) { // should test for init, but...
- return; // we already init this.
- }
- #ifdef DEBUG_ASYNC_LEDS
- pinMode(DEBUG_PIN_1, OUTPUT); digitalWrite(DEBUG_PIN_1, LOW);
- pinMode(DEBUG_PIN_2, OUTPUT); digitalWrite(DEBUG_PIN_2, LOW);
- pinMode(DEBUG_PIN_3, OUTPUT); digitalWrite(DEBUG_PIN_3, LOW);
- #endif
-
-
- //Serial.println("InitDMASettings");
- uint8_t dmaTXevent = _spi_hardware->tx_dma_channel;
- _count_pixels = _width*_height; // cache away the size of the display.
-
- // Serial.printf("cbDisplay: %u COUNT_WORDS_WRITE:%d(%x) spi_num:%d\n", _count_pixels, COUNT_WORDS_WRITE, COUNT_WORDS_WRITE, _spi_num);
- #if defined(__MK66FX1M0__)
- uint8_t cnt_dma_settings = 2; // how many do we need for this display?
- uint32_t COUNT_WORDS_WRITE = (_count_pixels) / 2;
- // The 240x320 display requires us to expand to another DMA setting.
- if (COUNT_WORDS_WRITE >= 32768) {
- COUNT_WORDS_WRITE = (_count_pixels) / 3;
- cnt_dma_settings = 3;
- }
- // T3.6
- //Serial.printf("CWW: %d %d %d\n", CBALLOC, SCREEN_DMA_NUM_SETTINGS, count_words_write);
- // Now lets setup DMA access to this memory...
- _cnt_dma_settings = cnt_dma_settings; // save away code that needs to update
- _dmasettings[_spi_num][0].sourceBuffer(&_pfbtft[1], (COUNT_WORDS_WRITE-1)*2);
- _dmasettings[_spi_num][0].destination(_pkinetisk_spi->PUSHR);
-
- // Hack to reset the destination to only output 2 bytes.
- _dmasettings[_spi_num][0].TCD->ATTR_DST = 1;
- _dmasettings[_spi_num][0].replaceSettingsOnCompletion(_dmasettings[_spi_num][1]);
-
- _dmasettings[_spi_num][1].sourceBuffer(&_pfbtft[COUNT_WORDS_WRITE], COUNT_WORDS_WRITE*2);
- _dmasettings[_spi_num][1].destination(_pkinetisk_spi->PUSHR);
- _dmasettings[_spi_num][1].TCD->ATTR_DST = 1;
- _dmasettings[_spi_num][1].replaceSettingsOnCompletion(_dmasettings[_spi_num][2]);
-
- if (cnt_dma_settings == 3) {
- _dmasettings[_spi_num][2].sourceBuffer(&_pfbtft[COUNT_WORDS_WRITE*2], COUNT_WORDS_WRITE*2);
- _dmasettings[_spi_num][2].destination(_pkinetisk_spi->PUSHR);
- _dmasettings[_spi_num][2].TCD->ATTR_DST = 1;
- _dmasettings[_spi_num][2].replaceSettingsOnCompletion(_dmasettings[_spi_num][3]);
- }
- // Sort of hack - but wrap around to output the first word again.
- _dmasettings[_spi_num][cnt_dma_settings].sourceBuffer(_pfbtft, 2);
- _dmasettings[_spi_num][cnt_dma_settings].destination(_pkinetisk_spi->PUSHR);
- _dmasettings[_spi_num][cnt_dma_settings].TCD->ATTR_DST = 1;
- _dmasettings[_spi_num][cnt_dma_settings].replaceSettingsOnCompletion(_dmasettings[_spi_num][0]);
-
- // Setup DMA main object
- //Serial.println("Setup _dmatx");
- _dmatx.begin(true);
- _dmatx.triggerAtHardwareEvent(dmaTXevent);
- _dmatx = _dmasettings[_spi_num][0];
- // probably could use const table of functio_ns...
- if (_spi_num == 0) _dmatx.attachInterrupt(dmaInterrupt);
- else if (_spi_num == 1) _dmatx.attachInterrupt(dmaInterrupt1);
- else _dmatx.attachInterrupt(dmaInterrupt2);
-
- #elif defined(__IMXRT1062__) // Teensy 4.x
- // See if moving the frame buffer to other memory that is not cached helps out
- // to remove tearing and the like...I know with 256 it will be either 256 or 248...
- _dma_buffer_size = ST77XX_DMA_BUFFER_SIZE;
- _dma_cnt_sub_frames_per_frame = (_count_pixels) / _dma_buffer_size;
- while ((_dma_cnt_sub_frames_per_frame * _dma_buffer_size) != (_count_pixels)) {
- _dma_buffer_size--;
- _dma_cnt_sub_frames_per_frame = (_count_pixels) / _dma_buffer_size;
- }
-
- #if defined(DEBUG_ASYNC_UPDATE)
- Serial.printf("DMA Init buf size: %d sub frames:%d spi num: %d\n", _dma_buffer_size, _dma_cnt_sub_frames_per_frame, _spi_num);
- #endif
-
- _dma_data[_spi_num]._dmasettings[0].sourceBuffer(_dma_data[_spi_num]._dma_buffer1, _dma_buffer_size*2);
- _dma_data[_spi_num]._dmasettings[0].destination(_pimxrt_spi->TDR);
- _dma_data[_spi_num]._dmasettings[0].TCD->ATTR_DST = 1;
- _dma_data[_spi_num]._dmasettings[0].replaceSettingsOnCompletion(_dma_data[_spi_num]._dmasettings[1]);
- _dma_data[_spi_num]._dmasettings[0].interruptAtCompletion();
-
- _dma_data[_spi_num]._dmasettings[1].sourceBuffer(_dma_data[_spi_num]._dma_buffer2, _dma_buffer_size*2);
- _dma_data[_spi_num]._dmasettings[1].destination(_pimxrt_spi->TDR);
- _dma_data[_spi_num]._dmasettings[1].TCD->ATTR_DST = 1;
- _dma_data[_spi_num]._dmasettings[1].replaceSettingsOnCompletion(_dma_data[_spi_num]._dmasettings[0]);
- _dma_data[_spi_num]._dmasettings[1].interruptAtCompletion();
-
- // Setup DMA main object
- //Serial.println("Setup _dmatx");
- // Serial.println("DMA initDMASettings - before dmatx");
- _dma_data[_spi_num]._dmatx.begin(true);
- _dma_data[_spi_num]._dmatx.triggerAtHardwareEvent(dmaTXevent);
- _dma_data[_spi_num]._dmatx = _dma_data[_spi_num]._dmasettings[0];
- // probably could use const table of functions...
- if (_spi_num == 0) _dma_data[_spi_num]._dmatx.attachInterrupt(dmaInterrupt);
- else if (_spi_num == 1) _dma_data[_spi_num]._dmatx.attachInterrupt(dmaInterrupt1);
- else _dma_data[_spi_num]._dmatx.attachInterrupt(dmaInterrupt2);
- #else
- // T3.5
- // Lets setup the write size. For SPI we can use up to 32767 so same size as we use on T3.6...
- // But SPI1 and SPI2 max of 511. We will use 480 in that case as even divider...
-
- uint32_t COUNT_WORDS_WRITE = (_count_pixels) / 2;
-
- // The 240x320 display requires us to expand to another DMA setting.
- if (COUNT_WORDS_WRITE >= 32768) {
- COUNT_WORDS_WRITE = (_count_pixels) / 3;
- }
- _dmarx.disable();
- _dmarx.source(_pkinetisk_spi->POPR);
- _dmarx.TCD->ATTR_SRC = 1;
- _dmarx.destination(_dma_dummy_rx);
- _dmarx.disableOnCompletion();
- _dmarx.triggerAtHardwareEvent(_spi_hardware->rx_dma_channel);
- // probably could use const table of functions...
- if (_spi_num == 0) _dmarx.attachInterrupt(dmaInterrupt);
- else if (_spi_num == 1) _dmarx.attachInterrupt(dmaInterrupt1);
- else _dmarx.attachInterrupt(dmaInterrupt2);
-
- _dmarx.interruptAtCompletion();
-
- // We may be using settings chain here so lets set it up.
- // Now lets setup TX chain. Note if trigger TX is not set
- // we need to have the RX do it for us.
- _dmatx.disable();
- _dmatx.destination(_pkinetisk_spi->PUSHR);
- _dmatx.TCD->ATTR_DST = 1;
- _dmatx.disableOnCompletion();
- // Current SPIN, has both RX/TX same for SPI1/2 so just know f
- if (_pspi == &SPI) {
- _dmatx.triggerAtHardwareEvent(dmaTXevent);
- _dma_write_size_words = COUNT_WORDS_WRITE;
- } else {
- _dma_write_size_words = 480;
- _dmatx.triggerAtTransfersOf(_dmarx);
- }
- //Serial.printf("Init DMA Settings: TX:%d size:%d\n", dmaTXevent, _dma_write_size_words);
-
- #endif
- _dma_state = ST77XX_DMA_INIT; // Should be first thing set!
- // Serial.println("DMA initDMASettings - end");
-
- }
- #endif
-
- void ST7735_t3::dumpDMASettings() {
- #ifdef DEBUG_ASYNC_UPDATE
- #if defined(__MK66FX1M0__)
- // T3.6
- Serial.printf("DMA dump TCDs %d\n", _dmatx.channel);
- dumpDMA_TCD(&_dmatx);
- dumpDMA_TCD(&_dmasettings[_spi_num][0]);
- dumpDMA_TCD(&_dmasettings[_spi_num][1]);
- dumpDMA_TCD(&_dmasettings[_spi_num][2]);
- dumpDMA_TCD(&_dmasettings[_spi_num][3]);
- #elif defined(__IMXRT1062__) // Teensy 4.x
- // Serial.printf("DMA dump TCDs %d\n", _dmatx.channel);
- dumpDMA_TCD(&_dma_data[_spi_num]._dmatx);
- dumpDMA_TCD(&_dma_data[_spi_num]._dmasettings[0]);
- dumpDMA_TCD(&_dma_data[_spi_num]._dmasettings[1]);
- #else
- Serial.printf("DMA dump TX:%d RX:%d\n", _dmatx.channel, _dmarx.channel);
- dumpDMA_TCD(&_dmatx);
- dumpDMA_TCD(&_dmarx);
- #endif
- #endif
-
- }
-
- bool ST7735_t3::updateScreenAsync(bool update_cont) // call to say update the screen now.
- {
- // Not sure if better here to check flag or check existence of buffer.
- // Will go by buffer as maybe can do interesting things?
- // BUGBUG:: only handles full screen so bail on the rest of it...
- // Also bail if we are working with a hardware SPI port.
- #ifdef ENABLE_ST77XX_FRAMEBUFFER
- if (!_use_fbtft || !_pspi) return false;
-
-
- #if defined(__MK64FX512__) || defined(__MK20DX256__) // If T3.5 only allow on SPI...
- // The T3.5 DMA to SPI has issues with preserving stuff like we want 16 bit mode
- // and we want CS to stay on... So hack it. We will turn off using CS for the CS
- // pin.
- if (!cspin && (_cs != 0xff)) {
- //Serial.println("***T3.5 CS Pin hack");
- pcs_data = 0;
- pcs_command = pcs_data | _pspi->setCS(_rs);
- pinMode(_cs, OUTPUT);
- cspin = portOutputRegister(digitalPinToPort(_cs));
- *cspin = 1;
- }
- #endif
-
- #ifdef DEBUG_ASYNC_LEDS
- digitalWriteFast(DEBUG_PIN_1, HIGH);
- #endif
- // Init DMA settings.
- initDMASettings();
-
- // Don't start one if already active.
- if (_dma_state & ST77XX_DMA_ACTIVE) {
- #ifdef DEBUG_ASYNC_LEDS
- digitalWriteFast(DEBUG_PIN_1, LOW);
- #endif
- return false;
- }
-
- #if defined(__MK66FX1M0__)
- //==========================================
- // T3.6
- //==========================================
- if (update_cont) {
- // Try to link in #3 into the chain (_cnt_dma_settings)
- _dmasettings[_spi_num][_cnt_dma_settings-1].replaceSettingsOnCompletion(_dmasettings[_spi_num][_cnt_dma_settings]);
- _dmasettings[_spi_num][_cnt_dma_settings-1].TCD->CSR &= ~(DMA_TCD_CSR_INTMAJOR | DMA_TCD_CSR_DREQ); // Don't interrupt on this one...
- _dmasettings[_spi_num][_cnt_dma_settings].interruptAtCompletion();
- _dmasettings[_spi_num][_cnt_dma_settings].TCD->CSR &= ~(DMA_TCD_CSR_DREQ); // Don't disable on this one
- _dma_state |= ST77XX_DMA_CONT;
- } else {
- // In this case we will only run through once...
- _dmasettings[_spi_num][_cnt_dma_settings-1].replaceSettingsOnCompletion(_dmasettings[_spi_num][0]);
- _dmasettings[_spi_num][_cnt_dma_settings-1].interruptAtCompletion();
- _dmasettings[_spi_num][_cnt_dma_settings-1].disableOnCompletion();
- _dma_state &= ~ST77XX_DMA_CONT;
- }
-
-
- #ifdef DEBUG_ASYNC_UPDATE
- dumpDMASettings();
- #endif
- beginSPITransaction();
-
- // Doing full window.
- setAddr(0, 0, _width-1, _height-1);
- writecommand(ST7735_RAMWR);
-
- // Write the first Word out before enter DMA as to setup the proper CS/DC/Continue flaugs
- writedata16(*_pfbtft);
- // now lets start up the DMA
- // volatile uint16_t biter = _dmatx.TCD->BITER;
- //DMA_CDNE_CDNE(_dmatx.channel);
- // _dmatx = _dmasettings[0];
- // _dmatx.TCD->BITER = biter;
- _dma_frame_count = 0; // Set frame count back to zero.
- _dmaActiveDisplay[_spi_num] = this;
- _dma_state |= ST77XX_DMA_ACTIVE;
- _pkinetisk_spi->RSER |= SPI_RSER_TFFF_DIRS | SPI_RSER_TFFF_RE; // Set DMA Interrupt Request Select and Enable register
- _pkinetisk_spi->MCR &= ~SPI_MCR_HALT; //Start transfers.
- _dmatx.enable();
- //==========================================
- // T4
- //==========================================
- #elif defined(__IMXRT1062__) // Teensy 4.x
- // TODO
-
- // Start off remove disable on completion from both...
- // it will be the ISR that disables it...
- _dma_data[_spi_num]._dmasettings[0].TCD->CSR &= ~( DMA_TCD_CSR_DREQ);
- _dma_data[_spi_num]._dmasettings[1].TCD->CSR &= ~( DMA_TCD_CSR_DREQ);
-
- #ifdef DEBUG_ASYNC_UPDATE
- dumpDMASettings();
- #endif
- // Lets copy first parts of frame buffer into our two sub-frames
- memcpy(_dma_data[_spi_num]._dma_buffer1, _pfbtft, _dma_buffer_size*2);
- memcpy(_dma_data[_spi_num]._dma_buffer2, &_pfbtft[_dma_buffer_size], _dma_buffer_size*2);
- _dma_pixel_index = _dma_buffer_size*2;
- _dma_sub_frame_count = 0; //
-
- beginSPITransaction();
- // Doing full window.
- setAddr(0, 0, _width-1, _height-1);
- writecommand_last(ST7735_RAMWR);
-
- // Update TCR to 16 bit mode. and output the first entry.
- _spi_fcr_save = _pimxrt_spi->FCR; // remember the FCR
- _pimxrt_spi->FCR = 0; // clear water marks...
- maybeUpdateTCR(_tcr_dc_not_assert | LPSPI_TCR_FRAMESZ(15) | LPSPI_TCR_RXMSK /*| LPSPI_TCR_CONT*/);
- // _pimxrt_spi->CFGR1 |= LPSPI_CFGR1_NOSTALL;
- // maybeUpdateTCR(_tcr_dc_not_assert | LPSPI_TCR_FRAMESZ(15) | LPSPI_TCR_CONT);
- _pimxrt_spi->DER = LPSPI_DER_TDDE;
- _pimxrt_spi->SR = 0x3f00; // clear out all of the other status...
-
- _dma_data[_spi_num]._dmatx.triggerAtHardwareEvent( _spi_hardware->tx_dma_channel );
-
-
- _dma_data[_spi_num]._dmatx = _dma_data[_spi_num]._dmasettings[0];
-
- _dma_data[_spi_num]._dmatx.begin(false);
- _dma_data[_spi_num]._dmatx.enable();
-
- _dma_frame_count = 0; // Set frame count back to zero.
- _dmaActiveDisplay[_spi_num] = this;
- if (update_cont) {
- _dma_state |= ST77XX_DMA_CONT;
- } else {
- _dma_state &= ~ST77XX_DMA_CONT;
-
- }
-
- _dma_state |= ST77XX_DMA_ACTIVE;
- #else
- //==========================================
- // T3.5
- //==========================================
-
- // lets setup the initial pointers.
- _dmatx.sourceBuffer(&_pfbtft[1], (_dma_write_size_words-1)*2);
- _dmatx.TCD->SLAST = 0; // Finish with it pointing to next location
- _dmarx.transferCount(_dma_write_size_words);
- _dma_count_remaining = _count_pixels - _dma_write_size_words; // how much more to transfer?
- //Serial.printf("SPI1/2 - TC:%d TR:%d\n", _dma_write_size_words, _dma_count_remaining);
-
- #ifdef DEBUG_ASYNC_UPDATE
- dumpDMASettings();
- #endif
-
- beginSPITransaction();
- // Doing full window.
- setAddr(0, 0, _width-1, _height-1);
- writecommand(ST7735_RAMWR);
-
- // Write the first Word out before enter DMA as to setup the proper CS/DC/Continue flaugs
- // On T3.5 DMA only appears to work with CTAR 0 so hack it up...
- _pkinetisk_spi->CTAR0 |= SPI_CTAR_FMSZ(8); // Hack convert from 8 bit to 16 bit...
-
- _pkinetisk_spi->MCR = SPI_MCR_MSTR | SPI_MCR_CLR_RXF | SPI_MCR_PCSIS(0x1F);
-
- _pkinetisk_spi->SR = 0xFF0F0000;
-
- // Lets try to output the first byte to make sure that we are in 16 bit mode...
- _pkinetisk_spi->PUSHR = *_pfbtft | SPI_PUSHR_CTAS(0) | SPI_PUSHR_CONT;
-
- if (_pspi == &SPI) {
- // SPI - has both TX and RX so use it
- _pkinetisk_spi->RSER = SPI_RSER_RFDF_RE | SPI_RSER_RFDF_DIRS | SPI_RSER_TFFF_RE | SPI_RSER_TFFF_DIRS;
-
- _dmarx.enable();
- _dmatx.enable();
- } else {
- _pkinetisk_spi->RSER = SPI_RSER_RFDF_RE | SPI_RSER_RFDF_DIRS ;
- _dmatx.triggerAtTransfersOf(_dmarx);
- _dmatx.enable();
- _dmarx.enable();
- }
-
- _dma_frame_count = 0; // Set frame count back to zero.
- _dmaActiveDisplay[_spi_num] = this;
- if (update_cont) {
- _dma_state |= ST77XX_DMA_CONT;
- } else {
- _dma_state &= ~ST77XX_DMA_CONT;
-
- }
-
- _dma_state |= ST77XX_DMA_ACTIVE;
- #endif
- #ifdef DEBUG_ASYNC_LEDS
- digitalWriteFast(DEBUG_PIN_1, LOW);
- #endif
- return true;
- #else
- return false; // no frame buffer so will never start...
- #endif
-
- }
-
- void ST7735_t3::endUpdateAsync() {
- // make sure it is on
- #ifdef ENABLE_ST77XX_FRAMEBUFFER
- if (_dma_state & ST77XX_DMA_CONT) {
- _dma_state &= ~ST77XX_DMA_CONT; // Turn of the continueous mode
- #if defined(__MK66FX1M0__)
- _dmasettings[_spi_num][_cnt_dma_settings].disableOnCompletion();
- #endif
- }
- #endif
- }
-
- void ST7735_t3::waitUpdateAsyncComplete(void)
- {
- #ifdef ENABLE_ST77XX_FRAMEBUFFER
- #ifdef DEBUG_ASYNC_LEDS
- digitalWriteFast(DEBUG_PIN_3, HIGH);
- #endif
-
- while ((_dma_state & ST77XX_DMA_ACTIVE)) {
- // asm volatile("wfi");
- };
- #ifdef DEBUG_ASYNC_LEDS
- digitalWriteFast(DEBUG_PIN_3, LOW);
- #endif
- #endif
- }
-
- #endif
-
- #endif
-
|