MicroMod Beta Testing

@KurtE
Can't seem to push the SPI Clock over 30Mhz for the ILI9341 - just shows a white screen if I do. Just an FYI
I know typically can not push it much especially over jumper wires.

If we really need to get it faster... We probably need a setup where camera and display are plugged in.

But not sure at this point how far to take it, as this is simply testing that their board is working...
 
Good luck with FlexIO for the camera - assuming you mean the 4bit FlexIO? Are you trying it with the library or started it with your initial test sketch - going to assume your initial sketch?

I'm working on FlexIO again today. Building test code inside your lib and targeting 8 bit mode, mostly just overriding the readFrame() function while I struggle to get it just working in any way at all. Will convert to a stop-start approach like Kurt's GPIO DMA when (if) I get the FlexIO timers working.

4 bit and single bit mode won't happen until much later, if at all. Not going to mess with that stuff until the breakout board I mentioned in msg #184 arrives. I sent the files only last Thursday, so they're still over a week or two away.

My FlexIO hope is to set up a single large DMA transfer on the rising edge of VSYNC and let FlexIO capture the entire video frame without any CPU usage, then give an interrupt when it's complete in the buffer. It's going to require a more complex timer setup than AN12686 and page 2908 in the reference manual, because we have extra junk to ignore on each HSYNC pulse after the 320 valid pixels. I'm still struggling to understand the finer points of FlexIO timers. NXP's documentation leaves a lot to be desired...
 
Hi Paul,

With the DMA stuff I found I needed to ignore 4 pixel clocks per HSYNC. I do it at the end of the row, not sure if best to split? Or not.

Keep meaning to update my internal FlexIO library to work with this. Also needing to update that there are 8 timers not 4 and the like. Maybe I will play with it and see about making lots Of Serial objects...

Will be interesting to see how well you breakout works!
 
Hi all
@KurtE beat me to it - was going to mention that @KurtE did a lot of work with FlexIO and he a library set up for it - not sure where the whole discussion is on the forum anymore

I'll second what Kurt said will be interesting to see how well that breakout board works with the Camera etc.
 
That is can the ILI9341 display display 60 full frames per second?
That is assuming 0 overhead each frame sends about 320*240*2 + 11 bytes (again not taking time for DC/CS changes)
So about 153611bytes per screen * 60 = 9216660 bytes per second and if each byte takes about 9 bits of data (byte plus gap, maybe closet to 10
Would imply SPI speed > 90mhz...

Another detail to keep in mind is the display redraws the screen from its own frame buffer at a speed probably less than 60 Hz. I recall seeing a register to adjust the internal refresh speed. But no matter what setting you use, the clock is from an RC oscillator that won’t be anywhere near as accurate as a crystal.
 
Just got around to pulling this morning's changes - will see where it stands - seems the DMA buffer will work for the Continuous sent to Processing without the bogus image result - will try that shortly.

Got unexpected distraction with filling new pickup with firewood and moving some logs with the neighbors.

That OSH full breakout looks like a nice tool to have - hopefully you'll get to see it in just one week.

Good luck with the FlexIO!

KurtE's DMA looks good. A bit pulsating - not the newest yet - but just reoriented ML carrier and camera on a phone stand so now a real live movie cam ... of me sitting here ... and not the ceiling.
 
Another detail to keep in mind is the display redraws the screen from its own frame buffer at a speed probably less than 60 Hz. I recall seeing a register to adjust the internal refresh speed. But no matter what setting you use, the clock is from an RC oscillator that won’t be anywhere near as accurate as a crystal.
Good question/point! As mentioned by Frank, he did increase the refresh rate to a higher speed.

As I mentioned in the previous post, the question is how much time to take to polish some of this stuff. If the idea is to test enough to make sure things are good enough for Sparkfun to release, I think we are there. Of course if they are at all considering a REV of the board for some reason, adding two more IO pins to the RTS, CTS pins would be great.

If the idea is to get some of this camera along with ILI display along well enough for something good enough to release as product to for example display video from camera, we probably have a ways to go. For example with ILI9341_t3n library, we have the ability to do things like setup to do things like go into continuous updates mode, have an interrupt when a frame output has completed, at that point we could copy in latest updated buffer. i.e. we could setup to double buffer and do most of it using interrupts. But the setup may be specific to what the example is trying to do.

But my question to myself (and others) is how much of my free Teensy time to spend on this versus things like MSC and MTP.... Hard to say.
 
Did a little bit more testing and one thing I noticed is that the framerate when set to 60 seems alot slower using the Sparkfun config rather than the default config. With the default config the osc_div is set to 2B while for the sparkfun case its 2a. Need to see if I can calculate what frame rate we really are seeing.
 
Just to satisfy my curiosity I put back into the loop Paul's vsych timing code and sure enough, whatever combination of settings Sparkfun is using seems off:

Using the 6Mhz clock and only changing frameRate to 30 and 60 here are the Vsynch timinings from the loope:
Code:
Default:
@30fps  = 30.69hz
@60fps  = 61.38hz

Sparkfun
@30fps  = 2.50hz
@60fps  = 5.01hz
which makes absolute sense now that I go back to original name for Sparkfun config file name:
Code:
hm01b0_raw8_qvga_8bits_lsb_5fps
which says its set up from 5fps. Guess lesson learned is don't mix up APIs. But no wonder everything works nicely at 5fps.
 
@mjs513: Made PR for the text.ino

Sublime 'code reformat' - lots of tabs showing - odd indents?

Added 'i' and 1 sec interval timer to track loop cnt and DMA callbacks
> DMA has minor affect on loop count/sec and gets 2-3 callbacks/second
Code:
Loops/sec:9896507	DMA CB/sec:3
Loops/sec:9875494	DMA CB/sec:3
Loops/sec:9911200	DMA CB/sec:2
// no continuous updates
Loops/sec:9999470	DMA CB/sec:0
> Cont update gets 1-2 updates per second - and that is the loop count.

Code:
Loops/sec:1	DMA CB/sec:0
Loops/sec:2	DMA CB/sec:0
> used that 1sec/timer to count up to 600 secs and blank screen if no user input.
--> it will flash black with continuous updates but not disable them - maybe it should have?

Added 'P' for continued timed updates to PDE
> went up to 1.6 seconds as PDE seems to end up getting behind - and when behind the outgoing USB SERIAL SPEW prevents incoming key presses to stop or affect the sketch.
Code:
Prior Image Sent! Took a new one.
Loops/sec:4306710	DMA CB/sec:0
Prior Image Sent! Took a new one.
Loops/sec:7248114	DMA CB/sec:0
Loops/sec:6049194	DMA CB/sec:0

Disabled readFrame() options when DMA is active as they can conflict?
> Didn't see path to use a stable buffer for PDE send when DMA was active?

I got a working ST7789 2" 320x240 display on the PJRC memory board easily working with latest KurtE/ST7735_t3/tree/char_bounds code. Has solder holes and on other end a plug included with the 8 wires to female ends on 8" wires that made connection easy!

Notes:
> Some DMA starts continue with 'skewed' buffer? {left/right halves wrapped or top/bottom - or some tearing garbage} : then a restart may work perfectly
> most PDE starts do nothing on first 'p' image send, and when they start often are skewed?
Here is an example of the skew seen here. Card right corner on left - and lower edge hand on mouse is top of frame, not sure where Teensy card bottom corner is - that white spot on top edge id the LCD corner in front of camer:
ProCam06.png
> image displayed in 'Selfy' mirror image mode - with board on phone holder I feel I'm being watched.
 
Last edited:
@KurtE - @Paul - @defragster - @all
More discoveries, realizations and decisions.

Doing some digging it appears that the framerate is dependent on 3 settings:
1. clock - osc_div which is done we use the function frameRate
2. frame length lines - 0x0340 (H), 0x0341 (L)
3. line length pck - 0x0341 (H), 0x0342

So looking at @KurtE's register comparison
Default:
Code:
[COLOR="#FF0000"]FRAME_LEN_LINES_H(340): 1(1)
FRAME_LEN_LINES_L(341): 4(4)[/COLOR]
LINE_LEN_PCK_H(342): 1(1)
LINE_LEN_PCK_L(343): 120(78)
Sparkfun:
Code:
[COLOR="#FF0000"]FRAME_LEN_LINES_H(340): 12(c)
FRAME_LEN_LINES_L(341): 122(7a)[/COLOR]
LINE_LEN_PCK_H(342): 1(1)
LINE_LEN_PCK_L(343): 119(77)

The primary difference is in the frame length lines registers. So I guess we need to decide which way we want to go with this - use Sparkfun settings or using the settings from OMV?? Guess this goes back to @KurtE's question what do we want this library to be. If we go with sparkfun doesn't make sense to have functions like frameRate or frameSize

There is something else but will make that a separate post which has nothing to do with this issue
 
@KurtE

I found the issue that you were having with having to skip 4 pixels. Turns out that the actual image size for QQVGA is 324x244 and not 320x240. The extra 4 pixels seem to be just border pixels. So I tested that change in the lib and the sketch and with a little modification it worked.
1. Changed writeRectangles to writeSubImageRect and retest continuous and snapshot and it worked.
2. With DMA I am having some problem. I see your:
Code:
	const uint16_t  _frame_ignore_cols = 4; // how many cols to ignore per row
but not sure what else needs to be changed.

@Paul - wondering if between this and the differences in the configs are also affecting your FlexIO stuff?

@defragster - added your sketch into the lib but with a slightly different name for now.
 
@mjs513 -

I never went through to see how many rows we ignored. Will be obvious when I can hook up LA to it... Or could write some extra code, probably like you did.
I did find out about the number of columns, by modifying your readFrame function in the line that is:
Code:
    while ((*_hrefPort & _hrefMask) != 0) ;  // wait for LOW
I had code that counted how many times the PCLK pin went high... Recorded that in a static array and printed it out at end...

Now if you make the frame the 324 larger size, my guess is you should be able to test simply by _frame_ignore_cols = 0;

That value is used in two places:
Code:
  _bytes_left_dma = (w + [COLOR="#FF0000"]_frame_ignore_cols[/COLOR]) * h * 2; // for now assuming color 565 image...
Which should reduce out fine, although maybe I need to update this one anyway, not sure we need the *2
It may not mater as we will bail from the DMA anyway when we fill the frame.

And again with the:
Code:
        // only process if href high...
        uint16_t b = *buffer >> 4;
        if (_frame_col_index < w) *_frame_buffer_pointer++ = b;
        _frame_col_index++;
        if (_frame_col_index == (w + [COLOR="#FF0000"]_frame_ignore_cols[/COLOR])) {
            // we just finished a row.
            _frame_row_index++;
            _frame_col_index = 0;
            _frame_row_buffer_pointer += w; // point to start of new row of buffer...
        }
        _bytes_left_dma--; // for now assuming color 565 image...
Again that simply reduces down, although could be reduced down to:
Code:
        // only process if href high...
        uint16_t b = *buffer >> 4;
        *_frame_buffer_pointer++ = b;
        _frame_col_index++;
        if (_frame_col_index == w) {
            // we just finished a row.
            _frame_row_index++;
            _frame_col_index = 0;
            _frame_row_buffer_pointer += w; // point to start of new row of buffer...
        }
        _bytes_left_dma--; // for now assuming color 565 image...

Again maybe I need to double check that double count might screw up now as it may still be asking for another DMA to complete and maybe not any bytes so it will wait until next frame starts...
 
Morning @KurtE

Yep - tried just making _frame_ignore_cols = 0 but the image messed up. Agree - not sure why you are multiplying by 2 since we only have grayscale. The *2 in the original readFrame was for color images. Will make it 0 again but delete the *2 and see if that helps.

EDIT:
@KurtE - tried a couple of things and still having problems. Picture is out of synch and shifted so getting what I originally was seeing.
 
Last edited:
Just pushed the current changes using subWriteRect and QVGA = 324x244. One other thing - took setpixformat out of the sketch and called it directly from init since this camera only supports grayscale. Also added a v2 test sketch to show vsync timings. @defragster haven't had time to play with your new sketch yet - still changing the library.
 
@mjs513 - you might push up what you have, either in main or some temporary branch and I will take a look.

Could be several things like: maybe I am not responding quick enough for the VSYNC to turn on the DMA. Probably not it, but...
Could speed it up, maybe interrupt on rising edge instead of trailing edge. Maybe raise ISR interrupt level, could create it's own ISR.

I believe it is Teensy pin 33(G10?) Which is on GPIO 4(9) pin 7,
So could change it back to GPIO4 and setup to use ISR: IRQ_GPIO4_0_15


Or could be my counts are off.

Probably again remove *2, then maybe have to count up how many bytes I ignored as the HSYNC bit was not set... then near end need to do fudge factor on
when to tell DMA to end... That is if we are getting near the end we may not tell it to read full buffer full, but only the remaining... But may need fudge factor
or maybe we say screw it, if I finished the last DMA buffer and I still have 3 pixels on the last row that I don't have data for as there were that many data items
I ignored, then say good enough especially if we don't use that last row anyway...

As for being out of sync. Should of course make sure the writeSubImageRect is working correctly. Also wonder if we are mainly wanting to go to displays and like if we should just save the 320*240 image?


Also another option we have instead of converting the 8 bit image to 16 bit image is to do something like, change:
Code:
void hm01b0_dma_callback(void *pfb) {
  //Serial.printf("Callback: %x\n", (uint32_t)pfb);
  if (tft.asyncUpdateActive()) return; // don't do anything while still active
  uint8_t *pframeBuffer = (uint8_t*)pfb;
  for(int i = 0; i < FRAME_HEIGHT*FRAME_WIDTH; i++) {
    uint8_t b = *pframeBuffer++;
    imageBuffer[i] = color565(b, b, b);
  }
  tft.writeRect(0, 0, tft.width(), tft.height(), imageBuffer);

  tft.updateScreenAsync();

  last_dma_frame_buffer = (uint16_t*)pfb;
}
Note: I have a change shown in this function, that don't try updating the display if we are already active updating the display...
To:
Code:
uint16_t mono_palette[256];
bool mono_palette_init = false;

void hm01b0_dma_callback(void *pfb) {
  //Serial.printf("Callback: %x\n", (uint32_t)pfb);
  if (tft.asyncUpdateActive()) return; // don't do anything while still active
  if (mono_palette_init) {
    mono_palette_init  = true;
    for (int i=0; i < 256; i++) mono_palette[i] = color565(i,i,i);
  }
  tft.writeRect8BPP(0, 0, tft.width(), tft.height(), pfb, mono_palette);

  tft.updateScreenAsync();

  last_dma_frame_buffer = (uint16_t*)pfb;
}
Note: I would put the init of the palette elsewhere, could even set it up statically and have it part of the PROGMEM...
Not sure how much speed this would increase, would remove the need to copy memory and extra buffers.

Or could setup for continuous screen updates, setup for Interrupts on frame completions and maybe half frame, could then have code that knows the last camera image received and copy in first part when working on second part, and second part on first... ...

Again lots of possible things to try. Not sure yet how far.
 
...

@defragster - added your sketch into the lib but with a slightly different name for now.

I started to do that - but some of the DMA disable stuff isn't compatible so switching that off is needed - and thought I saw you ask for a way to count DMA updates? And other than the Reformat because all the indents were deep and odd - didn't think it broke/changed anything in normal use - unless you had WIP changes not posted - which COdeComapre can help with.

Noticed CodeComapre will take to unrelated lines at times and give you the choice of 'either or' when shifting it 'side to side' - like taking out and #endif in exhange for something else.
 
@KurtE
Updates are already pushed to repository, see post 342, right before yours.

99% sure that the writeSubImageRect is working correctly because I am now using it for 's'napshot and 'continuous modes and its displaying correctly.

I did try ditching the *2 as well but it didn't help.

EDIT:
As a quick and dirty (skipframecount and delete *2) and using a modified callback
Code:
void hm01b0_dma_callback(void *pfb) {
  //Serial.printf("Callback: %x\n", (uint32_t)pfb);
  uint8_t *pframeBuffer = (uint8_t*)pfb;
  for(int i = 0; i < FRAME_HEIGHT*FRAME_WIDTH; i++) {
    uint8_t b = *pframeBuffer++;
    imageBuffer[i] = color565(b, b, b);
  }
[COLOR="#FF0000"]  //tft.writeRect(0, 0, tft.width(), tft.height(), imageBuffer);
  tft.writeSubImageRect(0, 0, tft.width(), tft.height(),  (FRAME_WIDTH - tft.width()) / 2, (FRAME_HEIGHT - tft.height()),
                          FRAME_WIDTH, FRAME_HEIGHT, imageBuffer);[/COLOR]
  tft.updateScreenAsync();

  last_dma_frame_buffer = (uint16_t*)pfb;
}
Its working for the most part at 30fps with no sparkfun config. At 60 the dma stops sending images after 1 frame. But now with the fix sparkfun not playing nice with DMA.

EDIT: to get DMA working with Sparkfun config have to use: _frame_ignore_cols = 4 if 0 gets upset so now wondering what the heck else they did.
 
I started to do that - but some of the DMA disable stuff isn't compatible so switching that off is needed - and thought I saw you ask for a way to count DMA updates? And other than the Reformat because all the indents were deep and odd - didn't think it broke/changed anything in normal use - unless you had WIP changes not posted - which COdeComapre can help with.

Noticed CodeComapre will take to unrelated lines at times and give you the choice of 'either or' when shifting it 'side to side' - like taking out and #endif in exhange for something else.

Yeah was going way deeper originally to see what was going on so started with Vsync. Want to see what you did and see I can merge but really distracted. I did remember to update the PDE to 324/244 though.

But to @ALL really need to decide which config with we want to standardize to.
 
More fiddling with FlexIO... and I finally have it somewhat working. For reasons I don't fully understand, it's capturing only 7 of every 8 pixels. So I added a bit of kludge code to add 4 white pixels to fill in the gaps, so the pixel it does capture line up.

flexio.jpg
(a lovely view of the underside of the microscope & a desk lamp on my workbench)


So far I'm only using polling to read the shift register buffers. Seems pointless to throw in the complexity of DMA until the capturing of all pixels is working.

You can also see some garbage in the last few rows. I'm currently just capturing all pixels and some code is shuffling the buffer around to delete the 4 extra pixels from each HSYNC, which leaves junk at the bottom.

If I don't get the missing 8th pixel problem solved today, I'll clean up the code a bit (mostly just move it to its own function) and send a pull request Monday so anyone who wants to play with it can see what I've (not quite correctly) done so far.
 
@Paul - looks like you are making good progress with it. Does your wiring do anything special? Or did your board just breakout the pins of the ribbon?

@mjs513 not much progress yet with DMA... But did do an experiment with the alternate way to output to the screen:

Defined a palette:
Code:
#define MCP(m) (uint16_t)(((m & 0xF8) << 8) | ((m & 0xFC) << 3) | (m >> 3))

static const uint16_t mono_palette[256] PROGMEM = {
  MCP(0x00),MCP(0x01),MCP(0x02),MCP(0x03),MCP(0x04),MCP(0x05),MCP(0x06),MCP(0x07),MCP(0x08),MCP(0x09),MCP(0x0a),MCP(0x0b),MCP(0x0c),MCP(0x0d),MCP(0x0e),MCP(0x0f),
  MCP(0x10),MCP(0x11),MCP(0x12),MCP(0x13),MCP(0x14),MCP(0x15),MCP(0x16),MCP(0x17),MCP(0x18),MCP(0x19),MCP(0x1a),MCP(0x1b),MCP(0x1c),MCP(0x1d),MCP(0x1e),MCP(0x1f),
  MCP(0x20),MCP(0x21),MCP(0x22),MCP(0x23),MCP(0x24),MCP(0x25),MCP(0x26),MCP(0x27),MCP(0x28),MCP(0x29),MCP(0x2a),MCP(0x2b),MCP(0x2c),MCP(0x2d),MCP(0x2e),MCP(0x2f),
  MCP(0x30),MCP(0x31),MCP(0x32),MCP(0x33),MCP(0x34),MCP(0x35),MCP(0x36),MCP(0x37),MCP(0x38),MCP(0x39),MCP(0x3a),MCP(0x3b),MCP(0x3c),MCP(0x3d),MCP(0x3e),MCP(0x3f),
  MCP(0x40),MCP(0x41),MCP(0x42),MCP(0x43),MCP(0x44),MCP(0x45),MCP(0x46),MCP(0x47),MCP(0x48),MCP(0x49),MCP(0x4a),MCP(0x4b),MCP(0x4c),MCP(0x4d),MCP(0x4e),MCP(0x4f),
  MCP(0x50),MCP(0x51),MCP(0x52),MCP(0x53),MCP(0x54),MCP(0x55),MCP(0x56),MCP(0x57),MCP(0x58),MCP(0x59),MCP(0x5a),MCP(0x5b),MCP(0x5c),MCP(0x5d),MCP(0x5e),MCP(0x5f),
  MCP(0x60),MCP(0x61),MCP(0x62),MCP(0x63),MCP(0x64),MCP(0x65),MCP(0x66),MCP(0x67),MCP(0x68),MCP(0x69),MCP(0x6a),MCP(0x6b),MCP(0x6c),MCP(0x6d),MCP(0x6e),MCP(0x6f),
  MCP(0x70),MCP(0x71),MCP(0x72),MCP(0x73),MCP(0x74),MCP(0x75),MCP(0x76),MCP(0x77),MCP(0x78),MCP(0x79),MCP(0x7a),MCP(0x7b),MCP(0x7c),MCP(0x7d),MCP(0x7e),MCP(0x7f),
  MCP(0x80),MCP(0x81),MCP(0x82),MCP(0x83),MCP(0x84),MCP(0x85),MCP(0x86),MCP(0x87),MCP(0x88),MCP(0x89),MCP(0x8a),MCP(0x8b),MCP(0x8c),MCP(0x8d),MCP(0x8e),MCP(0x8f),
  MCP(0x90),MCP(0x91),MCP(0x92),MCP(0x93),MCP(0x94),MCP(0x95),MCP(0x96),MCP(0x97),MCP(0x98),MCP(0x99),MCP(0x9a),MCP(0x9b),MCP(0x9c),MCP(0x9d),MCP(0x9e),MCP(0x9f),
  MCP(0xa0),MCP(0xa1),MCP(0xa2),MCP(0xa3),MCP(0xa4),MCP(0xa5),MCP(0xa6),MCP(0xa7),MCP(0xa8),MCP(0xa9),MCP(0xaa),MCP(0xab),MCP(0xac),MCP(0xad),MCP(0xae),MCP(0xaf),
  MCP(0xb0),MCP(0xb1),MCP(0xb2),MCP(0xb3),MCP(0xb4),MCP(0xb5),MCP(0xb6),MCP(0xb7),MCP(0xb8),MCP(0xb9),MCP(0xba),MCP(0xbb),MCP(0xbc),MCP(0xbd),MCP(0xbe),MCP(0xbf),
  MCP(0xc0),MCP(0xc1),MCP(0xc2),MCP(0xc3),MCP(0xc4),MCP(0xc5),MCP(0xc6),MCP(0xc7),MCP(0xc8),MCP(0xc9),MCP(0xca),MCP(0xcb),MCP(0xcc),MCP(0xcd),MCP(0xce),MCP(0xcf),
  MCP(0xd0),MCP(0xd1),MCP(0xd2),MCP(0xd3),MCP(0xd4),MCP(0xd5),MCP(0xd6),MCP(0xd7),MCP(0xd8),MCP(0xd9),MCP(0xda),MCP(0xdb),MCP(0xdc),MCP(0xdd),MCP(0xde),MCP(0xdf),
  MCP(0xe0),MCP(0xe1),MCP(0xe2),MCP(0xe3),MCP(0xe4),MCP(0xe5),MCP(0xe6),MCP(0xe7),MCP(0xe8),MCP(0xe9),MCP(0xea),MCP(0xeb),MCP(0xec),MCP(0xed),MCP(0xee),MCP(0xef),
  MCP(0xf0),MCP(0xf1),MCP(0xf2),MCP(0xf3),MCP(0xf4),MCP(0xf5),MCP(0xf6),MCP(0xf7),MCP(0xf8),MCP(0xf9),MCP(0xfa),MCP(0xfb),MCP(0xfc),MCP(0xfd),MCP(0xfe),MCP(0xff)
};
And then changed you 's' code to use it:
Code:
      case 's':
       {
          tft.fillScreen(TFT_BLACK);
          calAE();
          Serial.println("Reading frame");
          memset((uint8_t*)frameBuffer, 0, sizeof(frameBuffer));
          hm01b0.set_mode(HIMAX_MODE_STREAMING_NFRAMES, 1);
          hm01b0.readFrame(frameBuffer);
          Serial.println("Finished reading frame"); Serial.flush();
#if 1
          tft.setOrigin(-2, -2);
          tft.writeRect8BPP(0, 0, FRAME_WIDTH, FRAME_HEIGHT, frameBuffer, mono_palette);
          tft.setOrigin(0, 0);

#else
          //convert grayscale to rgb
          for(int i = 0; i < FRAME_HEIGHT*FRAME_WIDTH; i++) {
            imageBuffer[i] = color565(frameBuffer[i], frameBuffer[i], frameBuffer[i]);
          }
          tft.writeSubImageRect(0, 0, tft.width(), tft.height(),  (FRAME_WIDTH - tft.width()) / 2, (FRAME_HEIGHT - tft.height()),
                                  FRAME_WIDTH, FRAME_HEIGHT, imageBuffer);
#endif          
          ch = ' ';
          g_continuous_mode = false;
          break;
        }
Sort of a hack, but simply set the screen origin off the screen by 2 pixels in each direction and then told it to draw the whole image using the palette, and let the built
in clipping code take care of the part that won't fit...

Appears to work.

Edit: Again wondering about hook up... I did purchase a breakout from Amazon, which arrived:
IMG_0322.jpg
 
Last edited:
Does your wiring do anything special? Or did your board just breakout the pins of the ribbon?

Right now I'm using Sparkfun's ML carrier board with ILI9341 connected to the left side pins. Nothing special on the HM01B0 camera.

On the breakout board, which is still at least a week away, I put 2 camera connectors on the bottom side. One is wired for 4 bits with the signal names documented on the silkscreen. The other is wired for 8 bits exactly the same as Sparkfun's ML carrier. I also added the through-hole pads you wanted for the USB host signals.

micromod_breakout_bottom.jpg

4 bit mode uses only the high-numbered pins (29 and higher) so it doesn't conflict with I2S audio or any of the other stuff normally used with Teensy 4.0. Even if I get FlexIO working perfectly with 8 bits, I'm not going to touch 4 bit mode until these breakout boards arrive. But working or not, I will send a pull request tomorrow with my current FlexIO code for anyone who wants to see it.
 
@Paul
Very cool that you got some life with using FlexIO. Was looking at Kurt's lib this morning and my head hurt :). Oh just one thing the 4pixels is a 2 pixel border around the actual 320x240 image.

A quick question - on your breakout board how did you handle the 1.8v power to the camera.

@KurtE
Just put your mod for 's' and looks like it working without an issue. Was looking at the breakout board the other day but didn't know how to handle the 1.8v power which I just asked Paul about.

EDIT: Seems to work pretty good for 'continuous mode as well.
 
Back
Top