using tft.pushColor to display PROGMEM rgb565 bitmaps

Hello,

I am still toying with different ways of displaying numbers on an Adafrut 1.4’’ TFT color display (still haven’t found a way of doing that which satisfies the former web developer in me :slight_smile: ).

Suppose I put an rgb565 bitmap into PROGMEM like this:

static const uint32_t zero565[225] = {
  0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
  0xffffffff, 0xef7d738e, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00002124, 0xa5148c51, 0xffffffff,
  0xffffffff, 0xa5140000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x000039c7, 0x8c510020, 0x8c51ffff,
  0xffffffff, 0xffffc638, 0x21040000, 0x00000000, 0x00000000, 0x00000000, 0x18c36b4d, 0x4a490000, 0x73aeffff,
  0xfffff79e, 0x738e0000, 0x5aebffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffbdd7, 0x18e30020, 0x8410ffff,
  0xffffef7d, 0x632c0000, 0x4228dedb, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffb596, 0x18c30020, 0x8c71ffff,
  0xffffef5d, 0x5aeb0000, 0x528adefb, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffa534, 0x10a20841, 0x9cd3ffff,
  0xffffef5d, 0x528a0000, 0x5acbe71c, 0xffffffff, 0xffffffff, 0xffffffff, 0xffff9cf3, 0x10820861, 0xa514ffff,
  0xffffe73c, 0x42280000, 0x630ce73c, 0xffffffff, 0xffffffff, 0xffffffff, 0xffff9492, 0x08610861, 0xad75ffff,
  0xffffe71c, 0x39e70000, 0x6b6def5d, 0xffffffff, 0xffffffff, 0xffffffff, 0xffff8c51, 0x08611082, 0xbdd7ffff,
  0xffffdefb, 0x31860000, 0x73aeef7d, 0xffffffff, 0xffffffff, 0xffffffff, 0xffff7bef, 0x084110a2, 0xc638ffff,
  0xffffdedb, 0x212410a2, 0xce79ffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffbdd7, 0x18c310a2, 0xce79ffff,
  0xffffef7d, 0x4a69d6ba, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xad7552aa, 0xe71cffff,
  0xffffef5d, 0x4a49defb, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xad55528a, 0xef5dffff,
  0xffffce79, 0x08612124, 0xef5dffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffad55, 0x08412124, 0xef5dffff,
  0xffffce59, 0x08410000, 0xa514ffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffff528a, 0x00002965, 0xef7dffff,
  0xffffc618, 0x00000000, 0xa534ffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffff4a49, 0x00003186, 0xf7beffff,
  0xffffbdf7, 0x00000000, 0xad75ffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffdf4228, 0x000031a6, 0xffdfffff,
  0xffffb5b6, 0x00000020, 0xb596ffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xf7be39e7, 0x000039e7, 0xffffffff,
  0xffdfad75, 0x00000861, 0xbdd7ffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xef7d39c7, 0x00004228, 0xffffffff,
  0xffdfa534, 0x00001082, 0xbdf7ffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xe73c31a6, 0x00004a69, 0xffffffff,
  0xffdf9cf3, 0x00002965, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xdefb2965, 0x00005acb, 0xffffffff,
  0xffffffff, 0xd6ba2965, 0x00000000, 0x00000000, 0x00000000, 0x00001082, 0x632c5acb, 0x0000630c, 0xffffffff,
  0xffffa514, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x39c78c51, 0x00208c51, 0xffffffff,
  0xffffe73c, 0x630c0000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x39c79cd3, 0x94b2ffff, 0xffffffff
};

and then called it using this bit of code:

tft.setAddrWindow(50, 50, 68, 75);
for (int img  = 0;  img <= 225; img++){  
       tft.pushColor(zero565[img]);
}

Right now, (obviously?) this isn’t working, it sort of half looks like the number zero in a 7-segment font, as it is supposed to, but the image is somewhat garbled. But could it be made to work? I guess you’d somehow have to tell the display when a row and column starts and stops, right?

I am using an Atmega1284P-PU, so there’s enough memory space on it to store an entire set of bitmaps for the numbers from 0 to 9. Per bitmap, these seem to take up around one and a half percent of the chip’s program memory, so it’d be well manageable. And I would probably only be using this one font face.

Is PushColor accepting 32bit values (2x16bit pixels)? That seems unlikely. Rows and Columns are determined by setAddrWindow. You are defining a rectangle of either 18x25 or 19x26 (not sure which one is correct, it's been a while since I was looking at this stuff). Maybe try setAddrWindow(50, 50, 67, 74) and push 450x16bit pixels.

I am assuming you are using Adafruit_ST7735 library:

#include <Adafruit_ST7735.h>
Adafruit_ST7735 tft(10, 9, 8);

static const uint32_t zero565[225] = { // this is stored in SRAM
    0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
    0xffffffff, 0xef7d738e, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00002124, 0xa5148c51, 0xffffffff,
    0xffffffff, 0xa5140000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x000039c7, 0x8c510020, 0x8c51ffff,
    0xffffffff, 0xffffc638, 0x21040000, 0x00000000, 0x00000000, 0x00000000, 0x18c36b4d, 0x4a490000, 0x73aeffff,
    0xfffff79e, 0x738e0000, 0x5aebffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffbdd7, 0x18e30020, 0x8410ffff,
    0xffffef7d, 0x632c0000, 0x4228dedb, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffb596, 0x18c30020, 0x8c71ffff,
    0xffffef5d, 0x5aeb0000, 0x528adefb, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffa534, 0x10a20841, 0x9cd3ffff,
    0xffffef5d, 0x528a0000, 0x5acbe71c, 0xffffffff, 0xffffffff, 0xffffffff, 0xffff9cf3, 0x10820861, 0xa514ffff,
    0xffffe73c, 0x42280000, 0x630ce73c, 0xffffffff, 0xffffffff, 0xffffffff, 0xffff9492, 0x08610861, 0xad75ffff,
    0xffffe71c, 0x39e70000, 0x6b6def5d, 0xffffffff, 0xffffffff, 0xffffffff, 0xffff8c51, 0x08611082, 0xbdd7ffff,
    0xffffdefb, 0x31860000, 0x73aeef7d, 0xffffffff, 0xffffffff, 0xffffffff, 0xffff7bef, 0x084110a2, 0xc638ffff,
    0xffffdedb, 0x212410a2, 0xce79ffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffbdd7, 0x18c310a2, 0xce79ffff,
    0xffffef7d, 0x4a69d6ba, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xad7552aa, 0xe71cffff,
    0xffffef5d, 0x4a49defb, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xad55528a, 0xef5dffff,
    0xffffce79, 0x08612124, 0xef5dffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffad55, 0x08412124, 0xef5dffff,
    0xffffce59, 0x08410000, 0xa514ffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffff528a, 0x00002965, 0xef7dffff,
    0xffffc618, 0x00000000, 0xa534ffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffff4a49, 0x00003186, 0xf7beffff,
    0xffffbdf7, 0x00000000, 0xad75ffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffdf4228, 0x000031a6, 0xffdfffff,
    0xffffb5b6, 0x00000020, 0xb596ffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xf7be39e7, 0x000039e7, 0xffffffff,
    0xffdfad75, 0x00000861, 0xbdd7ffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xef7d39c7, 0x00004228, 0xffffffff,
    0xffdfa534, 0x00001082, 0xbdf7ffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xe73c31a6, 0x00004a69, 0xffffffff,
    0xffdf9cf3, 0x00002965, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xdefb2965, 0x00005acb, 0xffffffff,
    0xffffffff, 0xd6ba2965, 0x00000000, 0x00000000, 0x00000000, 0x00001082, 0x632c5acb, 0x0000630c, 0xffffffff,
    0xffffa514, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x39c78c51, 0x00208c51, 0xffffffff,
    0xffffe73c, 0x630c0000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x39c79cd3, 0x94b2ffff, 0xffffffff
};

void setup()
{
    tft.initR();
    tft.fillScreen(0x0000);
    tft.setAddrWindow(50, 50, 67, 74);       //windows are inclusive
    for (int img  = 0;  img < 225; img++) {  //counting elements
        tft.pushColor(zero565[img] >> 16);   //hi
        tft.pushColor(zero565[img]);         //lo
    }
}

void loop()
{
}

It seems a very odd way to store a bitmap. You generally store as an array of colours i.e. uint16_t
Note that your definition does not store in PROGMEM unless you specifically tell it.
In which case you can:

    for (int img  = 0;  img < 225; img++) {  //counting elements
        uint32_t twopixel = pgm_read_dword(&zero565[img]);
        tft.pushColor(twopixel >> 16);   //hi
        tft.pushColor(twopixel);         //lo
    }

I have corrected your loop counter. You were using 226 iterations.

David.

Edit. I am fascinated by the “colours” in your bitmap. On my display, it really looks just like BLACK or WHITE. e.g. 0xef5dffff is going to look almost WHITE for both pixels. 0x00002965 will look BLACK for the first pixel (hi),

Well by "toying", I meant still trying to get my head around a few things about different ways of displaying pixels on a TFT screen. And taking a few shots in the dark in the process ;)

I actually didn't realize I wasn't putting the bitmap in PROGMEM... sorry, it was very, very late last night here in Europe, so you're going to have to forgive me one or two big oversights in that respect...

david_prentice: I am fascinated by the "colours" in your bitmap. On my display, it really looks just like BLACK or WHITE. e.g. 0xef5dffff is going to look almost WHITE for both pixels. 0x00002965 will look BLACK for the first pixel (hi),

This was really just a test picture to see if and how this would work at all. I might make all the number bitmaps in a reddish color, I haven't decided yet.

The underlying problem is that I am simply not happy with the way the Adafruit fonts are rendered on the display, and my motivation is that by increasing the bit depth, I can get numbers to look a bit more "rounded off" on the screen.

I've considered just loading 24-bit number bitmaps from 0 to 9 from the display's SD card every time I want to display a value, but that seems a bit unnecessary, and I want to keep the display operational if, for whatever reason, the SD card fails. Putting them in PROGMEM, consindering that I've got an Atmega1284, seems like the better approach, if I really want to do it that way.

You normally describe Fonts as a monochrome bitmap. The Library can print any letter in whatever foreground colour (and background colour) that you like. You can use x2, x3, x4 but this looks very blocky. It could even do Rainbows if that takes your fancy.

You have a Tiny display. 128x160 is hardly going to want 18x25 letters. However, you might want some 18x25 digits. Adafruit_GFX handles the FreeFonts nicely. So you could have some attractive Fonts if you want.

Likewise, I suppose that you could render a font with shadows, perspective, .... All very relevant on a 800x480 display. A bit pointless on 128x160.

Yes, you could use 16-bit BMP or even 24-bit BMP full colour icons. They will probably not fit in your mega1284.

David.

I am aware that a 128x128 TFT will always have limitations.

The question is, how does one make the most of the display's possibilities and turn information that is printed out onto the display into something that doesn't just get the job done of conveying data and information to the user, but also does it in an aesthetically pleasing manner.

I've just about tried all the free Adafruit fonts. At the end of the day, they all look blocky. It may turn out that I am way off course in trying to use individual bitmaps to display numbers from 0 to 9, but then it will still be a lesson learned.

This is all for a CarDuino. The idea is to have a number of different "menu pages", which you will be able to navigate with three touch buttons (back, forward and set). Two values will be displayed per menu page, in which case I think 18x25 isn't so bad. Lengths will vary between two and five or six digits.

Given that as a driver you are supposed to focus on the road and not on your instrument cluster, that is still plenty of information to take in at a split second's glance. Also, they need to be a certain size so you won't have to strain your eyes too much while looking at them, all of which would take attention away from the road in front of you.

|500x375

In slightly smaller writing, the inside and outside temperatures will be displayed permanently at the bottom of the screen.

Don't mind the bits of garbled pixels, the entire code is still in experimental stage and there are bits in it that do nothing or just throw a bunch of pixels onto the screen.

The zeros in the first line were my attempt at making one-byte monochrome bitmaps using LCD Image Converter. This has produced unsatisfactory results, as you can see. Other software has led to even worse results.

As I've said a few times before, as a web developer, you just aren't used to certain limitations that come with using an 8-bit microcontroller and a stamp sized display. You are kind of reminded at every other turn that some things just aren't possible the way you envision them. That said, I think it's not absurd to try to get the most out of this technology visually, if that's one of your main concerns.

I have posted a FreeFonts version of the default UTFT Fonts before now. The SevenSegmentFont looks fine on a 128x128 screen. The BigFont and SmallFont are not very attractive.

However, the FreeFonts supplied with Adafruit_GFX give you a good choice of styles.

I am surprised that you are just using CYAN and BLACK when you have 65536 different colours.

David.

david_prentice: I have posted a FreeFonts version of the default UTFT Fonts before now. The SevenSegmentFont looks fine on a 128x128 screen. The BigFont and SmallFont are not very attractive.

However, the FreeFonts supplied with Adafruit_GFX give you a good choice of styles.

I think I have looked at your seven segment font; it's really good. But it's still not what I'd like to have.

david_prentice: I am surprised that you are just using CYAN and BLACK when you have 65536 different colours.

It's actually a kind of maroon (#8f0a0a, or RGB 143 10 10) and black. And a few specks of grey (#818181 or RGB 129 129 129), and a dot here and there of #ffcc00 yellow (RGB 255 204 0). Smartphone pictures in low light just don't capture that well, I'm sorry.

Anyway, I am in the process of composing a color scheme for this CarDuino display. And these are probably going to be my main colors.

Here's what warnings will look like that will appear on the screen (for a few seconds) when certain sensors of the CarDuino pick up faults or cautions... the design still isn't final, I'm sort of kicking around a few different ideas for it in my head at the moment and trying them out:

This will appear when the outside temperature, monitored by a DS18B20 sensor, goes below 5°C or 40°F. These fullscreen bitmaps will be stored on the display's SD card though, not on the chip.

On my "to-do list", btw, is trying to store them on the SD card in 565 format. To make those images load faster.

And here's the latest overhaul of the design for the menu screens:

Like I've said before; I'm a very "visual" kind of guy... and I want this CarDuino to be as visually pleasing as it will be technically complex. One of my side jobs used to be as a graphics designer, and I am way too OCD to ever accept a CarDuino screen that just throws out a couple of numbers in basic system font... :D And if further down the line with this project it turns out that my visual ideas will need more memory than a chip has got, I will just move up a chip... at the moment, I am confident that a 1284 will be enough... but there is still its bigger brother the Atmega256x... :D

It looks as if your graphics are relatively simple. You can display monochrome icons in whatever colours you want. And monochrome bitmaps use very little memory e.g. no need for an external SD card.

Likewise, smallish full-colour icons will fit in Flash. e.g. 40x40 = 3.2kB 40x40 monochrome = 200 bytes

If you are good at design, that is the difficult part (and most important for sales). Just ask if you want help with 2-colour, 16-colour, 256-colour, 65536-colour images.

I would develop on a MEGA2560 or even a Uno. It will come down to the number of icons / images.

David.

I think the 1284 should be enough. I plan to store most images on the SD card, and only the image bitmaps for the numbers in PROGMEM.

carguy: ...And if further down the line with this project it turns out that my visual ideas will need more memory than a chip has got, I will just move up a chip... at the moment, I am confident that a 1284 will be enough... but there is still its bigger brother the Atmega256x... :D

An upgrade to the ATmega2560 will not help if the FLASH memory is used to contain the image arrays due to a limitation in the Arduino environment. Essentially the problem is that PROGMEM arrays push the start address of the sketch executable up to higher addresses in memory, if that executable start address goes above 64K then the processor will not boot. Then the low cost upgrade options are a NodeMCU or an Arduino Due (low cost ones are clones).

If you want to store images as jpegs in FLASH then that is possible using this library however rendering jpeg involves a lot of maths and so the Mega will take ~800ms to render a 128x128 jpeg. The benefit though is that images are then compressed from 5 to 20 times in size.

@carguy

What ATmega1284 board do you have? (this may be the upload problem culprit!) What bootloader is loaded?

FYI Arduino IDE 1.6.8 has a bug that disagrees with some Chinese FTDI clones.

bodmer: An upgrade to the ATmega2560 will not help if the FLASH memory is used to contain the image arrays due to a limitation in the Arduino environment. Essentially the problem is that PROGMEM arrays push the start address of the sketch executable up to higher addresses in memory, if that executable start address goes above 64K then the processor will not boot.

I reckon I'll be fine though; these PROGMEM bitmaps should altogether only take up some 20 KB, for two different sizes of a seven-digit font with numbers from 0 to 9.

bodmer: If you want to store images as jpegs in FLASH then that is possible using this library however rendering jpeg involves a lot of maths and so the Mega will take ~800ms to render a 128x128 jpeg. The benefit though is that images are then compressed from 5 to 20 times in size.

In that case it's probably better to just keep fullscreen bitmaps or anything that's larger than a few KB on the SD card. My CarDuino will give out warnings and cautions as 128x128 bitmaps, and the plan is to store them on the SD card, maybe even as raw 565 data, because I've read somewhere that that will speed up load times compared to storing them as bmp.

bodmer: @carguy

What ATmega1284 board do you have? (this may be the upload problem culprit!) What bootloader is loaded?

FYI Arduino IDE 1.6.8 has a bug that disagrees with some Chinese FTDI clones.

As you can see, I've just deleted the post again in which I expressed my dissatisfaction with the 1284, and I was going to post it in another thread where I was already asking general questions about the Atmega1284.

I am trying to run an Atmega1284P-PU on a breadboard.

Setup as follows:

FTDI Friend --- > Atmega1284P-PU

GND --- GND Vcc --- Vcc TX --- RXD0 (pin 14) RX - TXD0 (pin 15) RTS --- 0.1 uF cap --- RTS (pin 9)

Also, a 100 uF cap across Vcc and GND

Uploads with the FTDI Friend are successful only one out of eight to ten times, they freeze in mid-upload, either by giving out a protocol error or "programmer is not responding".

It's really frustrating; I can half understand if a four-dollar FTDI device with a fake chip on it from China doesn't work. But the FTDI Friend was over $20, and it's performing this poorly.

You need a pullup to +5V and ideally a diode to +5V on the RST pin of the processor.

You can buy a Mega2560 clone or a Due clone for less than $20.

Even if your eventual target is not an Arduino, life is much simpler to develop with standard boards and standard libraries.

As I hinted earlier, I expect you will get everything inside a 32kB when it comes to production. You can store a lot of monochrome bitmaps for most of your icons.

But for development, just use a "big" chip like a 2560 or SAM3X. I doubt if your FTDI requires much to "fix" but you really want to design your app, not faff around with bad tools.

David.

bodmer:
You need a pullup to +5V and ideally a diode to +5V on the RST pin of the processor.

I’m Sorry, forgot to mention… I do have a pullup to 5V on the RTS pin.

david_prentice: You can buy a Mega2560 clone or a Due clone for less than $20.

Even if your eventual target is not an Arduino, life is much simpler to develop with standard boards and standard libraries.

As I hinted earlier, I expect you will get everything inside a 32kB when it comes to production. You can store a lot of monochrome bitmaps for most of your icons.

But for development, just use a "big" chip like a 2560 or SAM3X. I doubt if your FTDI requires much to "fix" but you really want to design your app, not faff around with bad tools.

David.

The 1284's main job is going to be collecting data from "satellite" circuits via I2C, and then processing the data and displaying it on the TFT. Using a few PROGMEM bitmaps to display the numbers/digits of the sensor readings, whereas the bulk of the image data, especially the full-screen warnings and cautions, will be stored on the SD card. Even the most modest MicroSD card these days will have 8 to 10 GB of memory, so you might as well do something with that, is my way of thinking ;)

Also, I'd like the CarDuino to be still operational if the SD card drive should fail for whatever reason. So I'd really like to have the numbers bitmaps in PROGMEM. And I'll probably also work on "alias" warnings in the event that the images on the SD card aren't accessible. You know, just a tft.fillScreen() command and then the respective warning in basic system font.

I'm not sure yet how much memory the program sketch itself and everything is going to take up; the 1284 is after all going to collect data from four to five different I2C slaves around the car, and it's going to have to process that data, maybe even make a note of some of it in EEPROM, and on top of this, I want it to control a TFT display.

Maybe a 1284 is a bit overblown for this project. But on the other hand, I'd rather have a higher "ceiling" in terms of chip resources to work with, so there will be little need for compromise.

As for "going into production" - I know others who drive the same car and who have expressed interest, to the point of having offered to "buy" the finished product from me once development of this CarDuino will be complete.

But to be honest, looking at cost calculations, limited market potential (this is for a low-volume 1990s sports convertible), and product liability (very important!), I'm more comfortable making it an open source, GPL license sort of thing. I will put an entire documentation online, including sketches, schematics, photos and parts lists, without asking a dime for it. In the end, this is simply a hobby project for my own personal car. If my project will make others happy as well, then to me that's worth more than having to worry about iffy profit margins.

I've got a marketing degree, so I'd probably not have that much trouble whipping this up into a business opportunity... but it's just not the direction into which I want to go with this project.

OK, you might consider using the ISP method of programming the board. This is my preferred method for "production" boards as then a bootloader is not needed and the board boots up instantly into the code. I have many USB to serial converters from China and they all work fine once the driver is loaded on the PC. So the problem is more likely to be the board you have rather than the converter.

Check the board processor oscillator is actually 16MHz as the frequency will affect the baud rate for upload.

If you are using a cheap switched mode mains power supply to power the board and connecting it to a PC you may have a "noise" problem. Try powerinr the board froma battery pack.

Bear in mind when you migrate a powering from a car that it is electrically quite an aggresive environment for electronics, for example during starting there are very large voltage spikes on the 12V supply that will easily destroy the processor, these spikes also get picked up on sensor lines and then blow the I/O pins so watch out and consider how the system is "grounded" and use shielded sensor wires. I2C lines are particularly susceptible to bus lockups due to spikes so choose a libray that supports a time-out and build in a system watchdog.

Good quality 12V accessory to USB power plugs can be used and typically have some spike suppression.