A era do FBCP-ILI9341 chegou ao fim. O FBCP-ILI9341 foi construído no topo da API Dispmanx de Videocore DispManx do Raspberry Pi.
No entanto, essa API foi obsoleta pela Fundação Raspberry Pi há algum tempo e, finalmente, obsoleta (= indisponível) no Raspberry Pi 5 e em diante.
Os distritos mais posteriores do Raspberry Pi não têm mais o DispManx ativo por padrão, mesmo para o PI0-PI4, mas, em vez disso, o Raspberry Pi passou para a pilha de compositores de driver KMS mais recente, que tem uma abstração diferente para integrar os drivers SPI. Outras pessoas estão desenvolvendo drivers de exibição SPI para o PI que são compatíveis com a pilha KMS. Vá para este tópico do Fórum Raspberry Pi para aprender mais.
Esse repositório é bom de ser considerado arquivado/obsoleto, embora eu não esteja marcando-o arquivado usando o recurso GitHub, pois esse recurso aparentemente também tornaria o rastreador de problemas somente leitura. Sinta -se à vontade para continuar discutindo questões no rastreador.
Este repositório implementa um driver para determinadas exibições de LCD baseadas em SPI para Raspberry Pi A, B, 2, 3, 4 e zero.
O trabalho foi motivado pela curiosidade depois de ver esta série de vídeos no canal Retomancave Youtube:
Nesses vídeos, o barramento SPI (GPIO) é referido como o gargalo. Exibe a atualização do SPI sobre um barramento de dados serial, transmitindo um bit por ciclo de relógio no barramento. Uma tela de 320x240x16bpp, portanto, requer uma taxa de relógio de ônibus SPI de 73,728MHz para obter uma frequência completa de atualização de 60fps. Poucos controladores SPI LCD podem se comunicar tão rápido na prática, mas são restringidos a, por exemplo, uma velocidade do relógio de ônibus SPI de 16 a 50 MHz, limitando significativamente a taxa máxima de atualização. Podemos fazer alguma coisa sobre isso?
O projeto FBCP-ILI9341 começou como um driver de exibição para o Adafruit 2.8 "320x240 TFT com tela de toque para tela Raspberry Pi que utiliza o controlador ILI9341. Nessa tela, o FBCP-ILI9341 pode atingir uma taxa de atualização de 60fps, dependendo do conteúdo Isso está sendo exibido.
Dado que o barramento SPI pode ser tão restrito na largura de banda, como é que o FBCP-ILI9341 parece ser capaz de atualizar até 60fps? A maneira como isso é alcançada é pelo que poderia ser chamado de atualizações de fluxo de exibição adaptativa . Em vez de fazer upload de cada pixel em cada ciclo de atualização de exibição, apenas os pixels realmente alterados na tela são enviados para o visor. Isso é factível porque o controlador ILI9341, como muitos outros controladores populares, possui funções de interface de comunicação que permitem especificar atualizações parciais da tela, até sub -rigpos ou mesmo níveis individuais de pixels. Isso permite superar o limite de largura de banda: por exemplo, em terremoto, mesmo que seja um jogo de ritmo rápido, em média, apenas cerca de 46% de todos os pixels na tela alteram cada quadro renderizado. Algumas partes, como a interface do usuário, permanecem praticamente constantes em vários quadros.
Outras otimizações também são utilizadas para espremer ainda mais desempenho:
#define NO_INTERLACING
no arquivo config.h
)O resultado é que o barramento SPI pode ser mantido próximo a 100% de saturação, ~ 94-97% usual, para maximizar a taxa de utilização do barramento, apenas transmitindo praticamente o número mínimo de bytes necessários para descrever cada novo quadro.
O motorista foi verificado para funcionar (pelo menos em algum momento do passado) nos seguintes sistemas:
Embora nem todas as placas sejam testadas ativamente, então YMMV, especialmente nas placas mais antigas. (Correções de bug bem -vindos, use https://elinux.org/rpi_hardwarehistory para identificar em qual quadro você está executando)
Os seguintes displays LCD foram testados:
Verifique as seções a seguir para configurar o driver.
Esse driver não utiliza o driver NOTRO/FBTFT FrameBuffer, de modo que precisa ser desativado se ativo. Ou seja, se o seu arquivo /boot/config.txt
tiver linhas que se parecem com dtoverlay=pitft28r, ...
, dtoverlay=waveshare32b, ...
ou dtoverlay=flexfb, ...
, eles devem ser removidos.
Este programa não utiliza o driver SPI padrão; portanto, uma linha como dtparam=spi=on
/boot/config.txt
também deve ser removida para que não cause conflitos.
Da mesma forma, se você tiver algum dtoverlays relacionado ao controlador de toque ativo, como dtoverlay=ads7846,...
ou qualquer coisa que tenha uma diretiva penirq=
, eles devem ser removidos para evitar conflitos. Seria possível adicionar suporte de toque ao FBCP-ILI9341 se alguém quiser fazer uma facada.
Corra no console do seu Raspberry Pi:
sudo apt-get install cmake
cd ~
git clone https://github.com/juj/fbcp-ili9341.git
cd fbcp-ili9341
mkdir build
cd build
cmake [options] ..
make -j
sudo ./fbcp-ili9341
Observe especialmente os dois pontos ..
Na linha CMake, que denota "Up One Directory" neste caso (em vez de se referir a "mais itens vá aqui").
Consulte a próxima seção para ver o que inserir em [Opções] .
Se você estiver executando o driver fbcp
existente, remova isso por exemplo, por meio de um sudo pkill fbcp
primeiro (enquanto executa no prompt SSH ou conectado a uma tela HDMI), esses dois não podem ser executados ao mesmo tempo. Se /etc/rc.local
ou /etc/init.d
contiver uma entrada para iniciar fbcp
na inicialização, essa diretiva deve ser excluída.
Geralmente, existem duas maneiras de configurar opções de construção, na linha de comando cmake e no arquivo config.h.
Na linha de comando cmake, as seguintes opções podem ser configuradas:
Ao usar um dos monitores que pilha no topo do Pi que já são reconhecidos pelo FBCP-ILI9341, você não precisa especificar as atribuições de pinos GPIO, mas o código FBCP-ILI9341 já possui. Passe uma das seguintes diretivas de cmake para os chapéus:
-DADAFRUIT_ILI9341_PITFT=ON
: Se você estiver executando o Adafruit 2.8 "320x240 TFT com tela de toque para Raspberry Pi (ou o Kit de Mini -Hat Adafruit Pitft 2.2". bandeira.-DADAFRUIT_HX8357D_PITFT=ON
: Se você tiver o pitft da Adafruit - montado 480x320 3,5 "TFT+touchscreen para tela Raspberry Pi, adicione esta linha.-DFREEPLAYTECH_WAVESHARE32B=ON
: Se você estiver executando no dispositivo CM3 ou zero Freeplay, passe este sinalizador. (Este não é um chapéu, mas ainda é uma atribuição de pino pré -configurada)-DWAVESHARE35B_ILI9486=ON
: Se especificado, tem como alvo uma tela de 3,5 "480x320 ILI9486.-DTONTEC_MZ61581=ON
: Se você estiver executando na tela TONTEC 3.5 "320x480 LCD, passe isso.-DPIRATE_AUDIO_ST7789_HAT=ON
: Se especificado, tem como alvo um áudio pirata 240x240, 1.3 polegadas IPS LCD LCD Hat para Raspberry Pi com ST7789 Display Controller-DWAVESHARE_ST7789VW_HAT=ON
: Se especificado, alvos A 240x240, 1,3 polegada IPS LCD LCD Hat para Raspberry Pi com ST7789VW Controlador de exibição.-DWAVESHARE_ST7735S_HAT=ON
: Se especificado, alvos A 128x128, 1,44 polegada LCD Chapéu de exibição para Raspberry Pi com ST7735S controlador de exibição.-DKEDEI_V63_MPI3501=ON
: Se especificado, alvo um KEDEI 3,5 polegadas spi tftlcd 480*320 16bit/18bit versão 6.3 2018/4/9 Display com MPI3501 Controlador de exibição. Se você conectou os fios diretamente no PI em vez de usar um chapéu na lista acima, precisará usar as diretivas de configuração abaixo. Além de especificar a tela, você também precisará informar ao FBCP-ILI9341 com quais pinos GPIO você conectou as conexões. Para configurar o controlador de exibição, passe um de:
-DILI9341=ON
: Se você estiver executando em qualquer outra tela genérica ILI9341, ou na tela waveShare32b que seja independente e não no dispositivo FreeplayTech CM3/Zero, passe este sinalizador.-DILI9340=ON
: Se você tiver uma tela ILI9340, passe esta diretiva. Os chipsets ILI9340 e ILI9341 são muito semelhantes, mas o ILI9340 não suporta todos os recursos no ILI9341 e eles serão desativados ou rebaixados.-DHX8357D=ON
: Se você tiver uma tela HX8357D, passe esta diretiva.-DSSD1351=ON
: Se você tiver uma tela OLED SSD1351, use isso.-DST7735R=ON
: Se você tiver uma tela ST7735R, use isso.-DST7789=ON
: Se você tiver uma tela ST7789, use isso.-DST7789VW=ON
: Se você tiver uma tela ST7789VW, use isso.-DST7735S=ON
: Se você tiver uma tela ST7735S, use isso.-DILI9486=ON
: Se você tiver uma tela ILI9486, passe esta diretiva.-DILI9486L=ON
: Se você tiver uma tela ILI9486L, passe esta diretiva. Observe que o ILI9486 e o ILI9486L são chips controladores bastante diferentes e mutuamente incompatíveis, portanto, tenha cuidado aqui identificando qual deles você tem. (ou apenas tente ambos, não deve quebrar se você identificado incorretamente)-DILI9488=ON
: Se você tiver uma tela ILI9488, passe esta diretiva.-DMPI3501=ON
: Se especificado, tem como alvo uma tela com o controlador de exibição MPI3501.Além disso, passe o seguinte para personalizar as atribuições de pinos GPIO que você usou:
-DGPIO_TFT_DATA_CONTROL=number
: especifica/substitui qual pino GPIO a ser usado para a linha Data/Control (DC) na comunicação SPI de 4 fios. Este número de pinos é especificado nos números BCM PIN. Se você possui uma tela SPI de 3 fios que não possui uma linha de dados/controle, defina esse valor como -1 , isto é -DGPIO_TFT_DATA_CONTROL=-1
para informar o FBCP-ILI9341 para segmentar 3 fios ("9 bits") SPI comunicação.-DGPIO_TFT_RESET_PIN=number
: especifica/substitui qual pino gpio a ser usado para a linha de redefinição de exibição. Este número de pinos é especificado nos números BCM PIN. Se omitido, supõe -se que a tela não tenha um pino de redefinição e esteja sempre ligado.-DGPIO_TFT_BACKLIGHT=number
: Especifica/substitui qual pino gpio a ser usado para a linha de luz de fundo da tela. Este número de pinos é especificado nos números BCM PIN. Se omitido, supõe-se que a tela não tenha um pino de luz de fundo controlado por GPIO e esteja sempre ligado. Se definir isso, consulte também a opção #define BACKLIGHT_CONTROL
em config.h
.O FBCP-ILI9341 sempre usa a porta SPI0 de hardware; portanto, os pinos MISO, MOSI, CLK e CE0 são sempre os mesmos e não podem ser alterados. O pino do miso não é realmente usado (pelo menos no momento), então você pode pular conectar esse. Se o seu monitor for desonesto que ignore a linha de habilitação do chip, você também poderá conectá -la ou também poderá fugir conectando -o ao solo se for pressionado para simplificar a fiação (dependendo da tela).
Para obter um bom desempenho dos monitores, você direcionará os monitores acima das especificações de velocidade nominal (as especificações classificadas rendem cerca de ~ 10fps, dependendo do visor). Devido a isso, você precisará configurar explicitamente a velocidade de destino em que deseja acionar a tela, porque devido às variações de fabricação que cada cópia de exibição atinge uma velocidade máxima diferente. Não há "velocidade padrão" que o FBCP-ILI9341 usaria. Definir a velocidade é feita através da opção
-DSPI_BUS_CLOCK_DIVISOR=even_number
: define o número do divisor de relógio que, juntamente com a opção Pi Core_freq = em /boot/config.txt
especifica a velocidade geral em que o barramento de comunicação SPI de exibição é acionado em. SPI_frequency = core_freq/divisor
. SPI_BUS_CLOCK_DIVISOR
deve ser um número par. PI 3B e zero W core_freq
é 400MHz e, geralmente, um valor -DSPI_BUS_CLOCK_DIVISOR=6
parece ser o melhor que uma tela ILI9341 pode fazer. Tente um valor maior se o visor mostrar saída corrupta ou um valor menor para obter uma largura de banda mais alta. Consulte Ili9341.h e waveShare35b.h para obter pontos de dados para ajustar o desempenho máximo do SPI. O valor inicial seguro pode ser algo como -DSPI_BUS_CLOCK_DIVISOR=30
. Existem algumas opções para dizer explicitamente qual placa PI você deseja segmentar. Estes devem ser auto -executados para você e geralmente não são necessários, mas, por exemplo, se você estiver compilando para outra placa PI de outro sistema ou deseja ser explícito, você pode tentar:
-DSINGLE_CORE_BOARD=ON
: Passe esta opção se estiver executando em um PI que tenha apenas um thread de hardware (Modelo A, PI Modelo B, Modelo B, Módulo 1, Pi Zero/Zero W). Se não estiver presente, auto -modedado.-DARMV6Z=ON
: Passe esta opção para otimizar especificamente o conjunto de instruções ARMV6Z (PI 1A, 1A+, 1B, 1B+, ZERO, ZERO W). Se não estiver presente, auto -modedado.-DARMV7A=ON
: Passe esta opção para otimizar especificamente o conjunto de instruções ARMV7-A (PI 2B <Rev 1.2). Se não estiver presente, auto -modedado.-DARMV8A=ON
: Passe esta opção para otimizar especificamente o conjunto de instruções ARMV8-A (PI 2B> = Rev. 1.2, 3b, 3b+, cm3, cm3 lite, 4b, cm4, PI400). Se não estiver presente, auto -modedado. As seguintes opções de construção são gerais para todos os displays e placas de PI, eles personalizam ainda mais a compilação:
-DBACKLIGHT_CONTROL=ON
: Se definido, Ativa o FBCP-ILI9341 para controlar a luz de fundo da tela no pino de luz de fundo fornecido. A tela vai dormir após um período de inatividade na tela. Caso contrário, a luz de fundo não é tocada.-DDISPLAY_CROPPED_INSTEAD_OF_SCALING=ON
: Se definido, e o quadro de vídeo de origem é maior que a resolução de vídeo do SPI Exibir, o vídeo de origem é apresentado na tela SPI criando partes dele em todas as direções, em vez de escalar.-DDISPLAY_BREAK_ASPECT_RATIO_WHEN_SCALING=ON
: Ao escalar o vídeo de origem para a exibição do SPI, a escala é executada por padrão seguinte, a proporção, adicionando caixas de correio/caixas de pilares, conforme necessário. Se isso for definido, o alongamento será realizado de proporção de quebra.-DSTATISTICS=number
: Especifica o nível de estatísticas de sobreposição a ser exibido na tela. 0: Desativado, 1: Ativado, 2: ativado e mostram o gráfico de intervalo de taxa de quadros também. O valor padrão é 1 (ativado).-DUSE_DMA_TRANSFERS=OFF
: Se especificado, desativa o uso de transferências de DMA (com ótimas despesas de uso de CPU perdido). Passe esta diretiva se o DMA estiver dando alguns problemas, por exemplo, como uma etapa de solução de problemas, se algo não estiver parecendo certo.-DDMA_TX_CHANNEL=<num>
: Especifica o número do canal DMA a ser usado para os comandos SPI Send. Altere isso se encontrar um conflito de canal DMA.-DDMA_RX_CHANNEL=<num>
: Especifica o número do canal DMA a ser usado para os comandos de recebimento SPI. Altere isso se encontrar um conflito de canal DMA.-DDISPLAY_SWAP_BGR=ON
: Se esta opção for passada, os canais de cores vermelhos e azuis serão revertidos (rgb <-> bgr). Algumas exibições têm um layout de subpixel de painel de cores oposto que o controlador de exibição não é responsável automaticamente; portanto, defina isso se o azul e o vermelho estiverem misturados.-DDISPLAY_INVERT_COLORS=ON
: Se esta opção for passada, a interpretação do valor da cor do pixel será revertida (branca = 0, preto = 31/63). Padrão: preto = 0, branco = 31/63. Passe esta opção se a imagem de exibição parecer uma cor negativa das cores reais.-DDISPLAY_ROTATE_180_DEGREES=ON
: Se definido, a exibição é girada 180 graus. Isso não afeta a saída HDMI, apenas a saída da tela SPI.-DLOW_BATTERY_PIN=<num>
: Especifica um pino GPIO que pode ser pesquisado para obter o estado da bateria. Por padrão, quando isso for definido, um ícone de bateria baixo será exibido se o pino for puxado baixo (consulte config.h
para maneiras pelas quais isso pode ser aprimorado). Além das diretivas cmake acima, existem várias defines espalhadas pela base de código, principalmente em config.h, que controlam diferentes opções de tempo de execução. Edite -os diretamente para ajustar ainda mais o comportamento do programa. Em particular, depois de terminar a configuração, convém criar com -DSTATISTICS=0
opção na linha de configuração do CMake.
Aqui está um exemplo completo do que digitar e executar, se você tiver o Adafruit 2.8 "320x240 TFT com tela de toque para Raspberry Pi com o controlador ILI9341:
cd ~
sudo apt-get install cmake
git clone https://github.com/juj/fbcp-ili9341.git
cd fbcp-ili9341
mkdir build
cd build
cmake -DSPI_BUS_CLOCK_DIVISOR=6 -DADAFRUIT_ILI9341_PITFT=ON ..
make -j
sudo ./fbcp-ili9341
Se o acima não funcionar, tente especificar -DSPI_BUS_CLOCK_DIVISOR=8
ou =10
para fazer com que a tela funcione um pouco mais lenta ou tente com -DUSE_DMA_TRANSFERS=OFF
para solucionar problemas se o DMA puder ser o problema. Se você estiver usando outro controlador de exibição que o ILI9341, usando um valor muito mais alto, poderá ser necessário 30 ou 40. Ao alterar as opções de CMake, você pode reemitir a linha de diretiva CMake sem precisar reclocar ou recriar o diretório build
. No entanto, você pode precisar excluir manualmente o arquivo cmakecache.txt entre a alteração das opções para evitar o CMake lembrando de configurações antigas.
Se você deseja fazer uma reconstrução completa do zero, pode rm -rf build
para excluir o diretório de compilação e recriá -lo para uma reconstrução limpa do zero. Não há nada de especial no nome ou local deste diretório, é apenas minha convenção habitual. Você também pode fazer a compilação em algum outro diretório em relação ao diretório FBCP-ILI9341, se quiser.
Para configurar o driver para ser lançado na inicialização, edite o arquivo /etc/rc.local
no modo sudo
e adicione uma linha
sudo /path/to/fbcp-ili9341/build/fbcp-ili9341 &
até o fim. Anote os ampeiros necessários &
no final dessa linha.
Por exemplo, se você usasse as etapas da linha de comando listadas acima para construir, o arquivo /etc/rc.local
receberia uma linha
sudo /home/pi/fbcp-ili9341/build/fbcp-ili9341 &
Se o nome de usuário da instalação do Raspberry Pi for outra coisa que o pi
padrão, altere o diretório de acordo para apontar para o diretório inicial do usuário. (Use pwd
para descobrir o diretório atual no terminal)
systemd
Como alternativa, em vez de modificar /etc/rc.local
, use o arquivo da unidade systemd
fornecido como abaixo:
sudo install -m 0644 -t /etc fbcp-ili9341.conf
sudo install -m 0644 -t /etc/systemd/system fbcp-ili9341.service
sudo systemctl daemon-reload
sudo systemctl enable fbcp && sudo systemctl start fbcp
Se o tamanho da saída HDMI padrão /dev/fb0
for diferente da resolução da tela, o tamanho do vídeo de origem será por padrão que será redimensionado para caber no tamanho da tela SPI. O FBCP-ILI9341 gerenciará a configuração desse redimensionamento, se necessário, e será feito pela GPU, para que o desempenho não seja muito impactado. No entanto, se as resoluções não corresponderem, o texto pequeno provavelmente parecerá ilegível. O redimensionamento será feito de maneira que preserva a proporção, portanto, se as proporções não corresponderem, as bordas pretas horizontais ou verticais aparecerão na tela. Se você não usar a saída HDMI, provavelmente é melhor configurar a saída HDMI para corresponder ao tamanho da tela SPI para que o redimensionamento não seja necessário. Isso pode ser feito definindo as seguintes linhas em /boot/config.txt
:
hdmi_group=2
hdmi_mode=87
hdmi_cvt=320 240 60 1 0 0 0
hdmi_force_hotplug=1
Se o seu monitor SPI tiver uma resolução diferente de 320x240, altere a parte 320 240
para por exemplo, 480 320
.
Essas linhas sugerem aplicativos nativos sobre o modo de exibição padrão e deixe -os renderizar à resolução nativa da tela TFT. No entanto, isso pode impedir o uso do conector HDMI, se a tela conectada HDMI não suportar uma resolução tão pequena. Como um compromisso, se as telas HDMI e SPI desejarem ser usadas ao mesmo tempo, alguma outra resolução compatível, como 640x480, poderá ser usada. Consulte a documentação do Raspberry Pi HDMI para obter as opções disponíveis para fazer isso.
A velocidade de atualização da tela é ditada pela velocidade do relógio do barramento SPI à qual a tela está conectada. Devido à maneira como o chip BCM2835 no Raspberry Pi funciona, não existe uma opção simples speed=xxx Mhz
que pode ser configurada para definir a velocidade do barramento. Em vez disso, a velocidade do barramento SPI é derivada de dois parâmetros separados: a frequência do núcleo do BCM2835 SOC em geral ( core_freq
in /boot/config.txt
) e a configuração do SPI Periférico CDIV
(divisor de relógio). Juntos, a velocidade do barramento SPI resultante é calculada com a fórmula SPI_speed=core_freq/CDIV
.
Para otimizar a tela para executar o mais rápido possível,
Ajuste o valor CDIV
passando a diretiva -DSPI_BUS_CLOCK_DIVISOR=number
na linha de comando cmake. Os valores possíveis são os números pares 2
, 4
, 6
, 8
, ...
Observe que, como CDIV
aparece no denominador na fórmula para SPI_speed
, valores menores resultam em maiores velocidades de barramento, enquanto os valores mais altos tornam a tela mais lenta. Inicialmente, quando você não sabe a rapidez com que sua tela pode ser executada, tente começar com uma configuração alta segura, como -DSPI_BUS_CLOCK_DIVISOR=30
e trabalhe com números menores para encontrar a velocidade máxima com a qual a tela pode lidar. Consulte a tabela no final do ReadMe para obter velocidades máximas de barramento observadas específicas para diferentes displays.
Verifique se a velocidade turbo. Isso é fundamental para boas taxas de quadros. No Raspberry Pi 3 Modelo B, o núcleo BCM2835 funciona por padrão a 400MHz (resultando em velocidade SPI 400/CDIV
MHZ) se houver energia suficiente fornecida ao PI e se a temperatura da CPU não exceder os limites térmicos. Se a CPU estiver inativa ou a tensão for baixa, o núcleo BCM2835 reverterá para o estado não-turbo de 250MHz, resultando em velocidade SPI 250/CDIV
MHZ. Esse efeito da velocidade do turbo no desempenho é significativo, uma vez que 400MHz vs não-turbo 250MHz chegam a +60% de mais largura de banda. Obtendo 60fps em terremoto, Sonic ou Tyrian geralmente requer essa frequência turbo, mas os jogos emulados por NES e C64 geralmente podem atingir 60fps, mesmo com o estoque de 250 MHz. Se, por algum motivo, a proteção de subconstração estiver aumentando, mesmo quando uma potência suficiente deve ser alimentada, você pode forçar o turbo quando a baixa tensão estiver presente, definindo o valor avoid_warnings=2
no arquivo /boot/config.txt
.
Talvez um pouco contra -intuitivamente, coloque o núcleo. Definir uma frequência de núcleo menor do que o Turbo de 400 MHz padrão pode ativar o uso de um divisor de relógio menor para obter uma velocidade de barramento SPI mais alta resultante. Por exemplo, se com o padrão core_freq=400
spi CDIV=8
obras (resultando na velocidade do barramento spi 400MHz/8=50MHz
), mas CDIV=6
não ( 400MHz/6=66.67MHz
foi demais), você pode tentar diminuir core_freq=360
e defina CDIV=6
para obter uma velocidade efetiva do barramento SPI de 360MHz/6=60MHz
, um meio termo entre os dois que talvez funcionem. O Balancing core_freq=
e as opções CDIV
permite encontrar a velocidade máxima do barramento SPI até os últimos KHz que o controlador de exibição pode tolerar. Pode -se também tentar a direção oposta e o overclock, mas isso, é claro, tem todos os problemas que surgem quando overclock. O Underclocking tem a desvantagem de que o PI é mais lento em geral; portanto, essa é certamente uma troca.
Por outro lado, é desejável controlar quanto tempo da CPU FBCP-ILI9341 tem permissão para usar. As configurações de construção padrão são ajustadas para maximizar a taxa de atualização de exibição às custas do consumo de energia no PI 3B. No Pi Zero, o oposto é feito, ou seja, por padrão, o driver otimiza para economia de bateria em vez da velocidade máxima de atualização da tela. As seguintes opções podem ser controladas para equilibrar entre esses dois:
A principal opção para controlar o aspecto de uso da CPU vs de desempenho é a opção #define ALL_TASKS_SHOULD_DMA
em config.h
. Ativar essa opção reduzirá bastante o uso da CPU. Se essa opção estiver desativada, a utilização do barramento SPI é maximizada, mas o uso da CPU pode ser de até 80%-120%. Quando essa opção está ativada, o uso da CPU geralmente é de cerca de 15%a 30%. O uso máximo da CPU ocorre ao assistir a um vídeo ou jogar um jogo em movimento rápido. Se nada estiver mudando na tela, o consumo da CPU do motorista deve cair muito perto de 0-5%. Por padrão, #define ALL_TASKS_SHOULD_DMA
está ativado para Pi Zero, mas desativado para Pi 3b.
A opção cmake -DUSE_DMA_TRANSFERS=ON
sempre deve ser ativada para um bom uso de baixa CPU. Se as transferências de DMA estiverem desativadas, o driver será executado no modo SPI em consultório, que geralmente utiliza um núcleo único dedicado do tempo da CPU. Se as transferências de DMA estiverem causando problemas, tente ajustar os canais de envio e recebimento DMA para usar para comunicação SPI com -DDMA_TX_CHANNEL=<num>
e -DDMA_RX_CHANNEL=<num>
opções cmake.
A sobreposição de estatísticas imprime informações detalhadas sobre o estado de execução. Desativar a sobreposição com -DSTATISTICS=0
opção para cmake melhora o desempenho e reduz o uso da CPU. Se você deseja continuar imprimindo estatísticas, tente aumentar o intervalo com a opção #define STATISTICS_REFRESH_INTERVAL <timeInMicroseconds>
na opção Config.h.
Ativar #define USE_GPU_VSYNC
reduz o consumo de CPU, mas devido ao Raspberrypi/Userland #440 pode causar gagueira. Desativar #defined USE_GPU_VSYNC
produz menos gagueira, mas devido ao Raspberrypi/Userland #440, aumenta o consumo de energia da CPU.
A opção #define SELF_SYNCHRONIZE_TO_GPU_VSYNC_PRODUCED_NEW_FRAMES
pode ser usada em conjunto com #define USE_GPU_VSYNC
para tentar encontrar um meio termo entre Raspberrypi/Userland #440 questões - moderadas a pouca gaveta, enquanto não tentando consumir muito CPU. Tente experimentar ativar ou desativar essa configuração.
Existem várias opções #define SAVE_BATTERY_BY_x
em Config.h, que não são ativadas para estar ativado. Estes devem ser seguros para usar sempre sem trocas. Se você estiver enfrentando problemas de latência ou desempenho, tente alterná -los para solucionar problemas.
A opção #define DISPLAY_FLIP_ORIENTATION_IN_SOFTWARE
causa um pouco de uso extra da CPU; portanto, desativará um pouco a carga da CPU.
Se o seu barramento de exibição SPI puder correr muito rápido em comparação com o tamanho da tela e a quantidade de conteúdo que muda na tela, você pode tentar ativar #define UPDATE_FRAMES_IN_SINGLE_RECTANGULAR_DIFF
na opção em config.h
para reduzir o uso da CPU às despesas de aumentar O número de bytes enviados sobre o ônibus. Observa -se que isso tem um grande efeito no Pi Zero, então vale a pena conferir especialmente lá.
Se o barramento de exibição do SPI puder correr muito rápido (ou você não se importa com a taxa de quadros, mas apenas com baixo uso da CPU), você pode tentar ativar #define UPDATE_FRAMES_WITHOUT_DIFFING
Opção em config.h
para renunciar à Delta Delta Adaptiva opção completamente. Isso será revertido para atualizações ingênuas de quadros completos para o uso geral de CPU absolutamente mínimo.
A opção #define RUN_WITH_REALTIME_THREAD_PRIORITY
pode ser ativada para fazer o driver executar na prioridade do processo em tempo real. No entanto, isso pode bloquear o sistema, mas ainda disponibilizado para experimentação avançada.
Em display.h
existe uma opção #define TARGET_FRAME_RATE <number>
. Definir isso como um valor menor, como 30, trocará a taxa de atualização para reduzir o consumo de CPU.
Um aspecto agradável do FBCP-ILI9341 é que ele introduz muito pouca sobrecarga de latência: em uma tela ILI9341 de 119Hz, o FBCP-ILI9341 obtém pixels como resposta da entrada GPIO à tela em menos de 16,66 ms. Eu só tenho uma câmera de gravação de 120fps, portanto, não posso medir facilmente atrasos mais curtos que isso, mas a estimativa estatística aproximada das imagens de vídeo em movimento lento sugere que esse atraso pode ser tão baixo quanto 2-3 ms, dominado pela taxa de atualização do painel de ~ 8,4mecs do ILI9341.
Isso não significa que a entrada geral para exibir a latência nos jogos seria tão imediata. Testar brevemente um jogo NES emulado na RetroPie sugere uma latência total de cerca de 60 a 80 ms. Essa latência é causada pela sobrecarga do emulador de jogo NES e pela latência extra adicionada pelo Linux, Dispmanx e GPU Rendering e GPU Framebuffer Snapshotting. (Se você executou o FBCP-ILI9341 como uma biblioteca estática ignorando o Dispmanx e a pilha da GPU, ligando diretamente sua lógica de entrada e aplicativo GPIO ao FBCP-ILI9341, você seria capaz de chegar a esses poucos MSes de latência geral, como mostrado no vídeo de entrada de gpio acima)
É interessante ARTABILIDADE DE LATRENCA.
Infelizmente, uma limitação de exibições conectadas ao SPI é que o sinal da linha VSYNC não está disponível nos controladores de exibição quando eles estão em execução no modo SPI, portanto, não é possível fazer atualizações bloqueadas do VSYNC, mesmo que a largura de banda do barramento SPI na tela tenha sido rápida o suficiente . Por exemplo, os 4 telas ILI9341 que eu tenho podem ser executados mais rápido que 75MHz, para que a largura de banda do barramento SPI, em termos de largura vsync since the display controllers do not report it. (If you do know of a display that does actually expose a vsync clock signal even in SPI mode, you can try implementing support to locking on to it)
You can however choose between two distinct types of tearing artifacts: straight line tearing and diagonal tearing . Whichever looks better is a bit subjective, which is why both options exist. I prefer the straight line tearing artifact, it seems to be less intrusive than the diagonal tearing one. To toggle this, edit the option #define DISPLAY_FLIP_ORIENTATION_IN_SOFTWARE
in config.h
. When this option is enabled, fbcp-ili9341 produces straight line tearing, and consumes a tiny few % more CPU power. By default Pi 3B builds with straight line tearing, and Pi Zero with the faster diagonal tearing. Check out the video Latency and tearing test #2: GPIO input to display latency in fbcp-ili9341 and tearing modes to see in slow motion videos how these two tearing modes look like.
Another option that is known to affect how the tearing artifact looks like is the internal panel refresh rate. For ILI9341 displays this refresh rate can be adjusted in ili9341.h
, and this can be set to range between ILI9341_FRAMERATE_61_HZ
and ILI9341_FRAMERATE_119_HZ
(default). Slower refresh rates produce less tearing, but have higher input-to-display latency, whereas higher refresh rates will result in the opposite. Again visually the resulting effect is a bit subjective.
To get tearing free updates, you should use a DPI display, or a good quality HDMI display. Beware that cheap small 3.5" HDMI displays such as KeDei do also tear - that is, even if they are controlled via HDMI, they don't actually seem to implement VSYNC timed internal operation.
Having no vsync is not all bad though, since with the lack of vsync, SPI displays have the opportunity to obtain smoother animation on content that is not updating at 60Hz. It is possible that content on the SPI display will stutter even less than what DPI or HDMI displays on the Pi can currently provide (although I have not been able to test this in detail, except for the KeDei case above).
The main option that affects smoothness of display updates is the #define USE_GPU_VSYNC
line in config.h
. If this is enabled, then the internal Pi GPU HDMI vsync clock is used to drive frames onto the display. The Pi GPU clock runs at a fixed rate that is independent of the content. This rate can be discovered by running tvservice -s
on the Pi console, and is usually 59Hz or 60Hz. If your application renders at this rate, animation will look smooth, but if not, there will be stuttering. For example playing a PAL NES game that updates at 50Hz with HDMI clock set at 60Hz will cause bad microstuttering in video output if #define USE_GPU_VSYNC
is enabled.
If USE_GPU_VSYNC
is disabled, then a busy spinning GPU frame snapshotting thread is used to drive the updates. This will produce smoother animation in content that does not maintain a fixed 60Hz rate. Especially in OpenTyrian, a game that renders at a fixed 36fps and has slowly scrolling scenery, the stuttering caused by USE_GPU_VSYNC
is particularly visible. Running on Pi 3B without USE_GPU_VSYNC
enabled produces visually smoother looking scrolling on an Adafruit 2.8" ILI9341 PiTFT set to update at 119Hz, compared to enabling USE_GPU_VSYNC
on the same setup. Without USE_GPU_VSYNC
, the dedicated frame polling loop thread "finds" the 36Hz update rate of the game, and then pushes pixels to the display at this exact rate. This works nicely since SPI displays disregard vsync - the result is that frames are pushed out to the SPI display immediately as they become available, instead of pulling them at a fixed 60Hz rate like HDMI does.
A drawback is that this kind of polling consumes more CPU time than the vsync option. The extra overhead is around +34% of CPU usage compared to the vsync method. It also requires using a background thread, and because of this, it is not feasible to be used on a single core Pi Zero. If this polling was unnecessary, this mode would also work on a Pi Zero, and without the added +34% CPU overhead on Pi 3B. See the Known Issues section below for more details.
There are two other main options that affect frame delivery timings, #define SELF_SYNCHRONIZE_TO_GPU_VSYNC_PRODUCED_NEW_FRAMES
and #define SAVE_BATTERY_BY_PREDICTING_FRAME_ARRIVAL_TIMES
. Check out the video fbcp-ili9341 frame delivery smoothness test on Pi 3B and Adafruit ILI9341 at 119Hz for a detailed side by side comparison of these different modes. The conclusions drawn from the four tested scenarios in the video are:
1. vc_dispmanx_vsync_callback() (top left) , set #define USE_GPU_VSYNC
and unset #define SELF_SYNCHRONIZE_TO_GPU_VSYNC_PRODUCED_NEW_FRAMES
:
This mode uses the DispmanX HDMI vsync signal callback to drive frames to the display.
Prós:
Contras:
2. vc_dispmanx_vsync_callback() + self synchronization (top right) , set #define USE_GPU_VSYNC
and #define SELF_SYNCHRONIZE_TO_GPU_VSYNC_PRODUCED_NEW_FRAMES
:
This mode uses the GPU vsync signal, but also aims to find and synchronize to the edge trigger when content is producing frames. This is the default build mode on Pi Zero.
Prós:
Contras:
3. gpu polling thread + sleep heuristic (bottom left) , unset #define USE_GPU_VSYNC
and set #define SAVE_BATTERY_BY_PREDICTING_FRAME_ARRIVAL_TIMES
:
This mode runs a dedicated background thread that drives frames from the GPU to the SPI display. This is the default build mode on Pi 3B.
Prós:
Contras:
4. gpu polling thread without sleeping (bottom right) , unset #define USE_GPU_VSYNC
and unset #define SAVE_BATTERY_BY_PREDICTING_FRAME_ARRIVAL_TIMES
:
This mode runs the dedicated GPU thread as fast as possible, without attempting to sleep CPU.
Prós:
Contras:
Be aware of the following limitations:
vc_dispmanx_snapshot()
API, and the obtained pixels are then routed on to the SPI-based display. This kind of polling is performed, since there does not exist an event-based mechanism to get new frames from the GPU as they are produced. The result is inefficient and can easily cause stuttering, since different applications produce frames at different paces. Ideally the code would ask the VideoCore API to receive finished frames in callback notifications immediately after they are rendered , but this kind of functionality does not exist in the current GPU driver stack. In the absence of such event delivery mechanism, the code has to resort to polling snapshots of the display framebuffer using carefully timed heuristics to balance between keeping latency and stuttering low, while not causing excessive power consumption. These heuristics keep continuously guessing the update rate of the animation on screen, and they have been tuned to ensure that CPU usage goes down to 0% when there is no detected activity on screen, but it is certainly not perfect. This GPU limitation is discussed at raspberrypi/userland#440. If you'd like to see fbcp-ili9341 operation reduce latency, stuttering and power consumption, please throw a (kind!) comment or a thumbs up emoji in that bug thread to share that you care about this, and perhaps Raspberry Pi engineers might pick the improvement up on the development roadmap. If this issue is resolved, all of the #define USE_GPU_VSYNC
, #define SAVE_BATTERY_BY_PREDICTING_FRAME_ARRIVAL_TIMES
and #define SELF_SYNCHRONIZE_TO_GPU_VSYNC_PRODUCED_NEW_FRAMES
hacks from the previous section could be deleted from the driver, hopefully leading to a best of all worlds scenario without drawbacks. /boot/config.txt
and configure all applications to never change that at runtime. 400/250=+60%
as well. Therefore when choosing the SPI CDIV
value to use, one has to pick one that works for both idle and turbo clock speeds. Conversely, the BCM core reverts to non-turbo speed when there is only light CPU load active, and this slows down the display, so if an application is graphically intensive but light on CPU, the SPI display bus does not get a chance to run at maximum speeds. A way to work around this is to force the BCM core to always stay in its turbo state with force_turbo=1
option in /boot/config.txt
, but this has an unfortunate effect of causing the ARM CPU to always run in turbo speed as well, consuming excessive amounts of power. At the time of writing, there does not yet exist a good solution to have both power saving and good performance. This limitation is being discussed in more detail at raspberrypi/firmware#992. For more known issues and limitations, check out the bug tracker, especially the entries marked retired , for items that are beyond current scope.
By default fbcp-ili9341 builds with a statistics overlay enabled. See the video fbcp-ili9341 ported to ILI9486 WaveShare 3.5" (B) SpotPear 320x480 SPI display to find details on what each field means. Build with CMake option -DSTATISTICS=0
to disable displaying the statistics. You can also try building with CMake option -DSTATISTICS=2
to show a more detailed frame delivery timings histogram view, see screenshot and video above.
The fbcp
part in the name means framebuffer copy ; specifically for the ILI9341 controller. fbcp-ili9341 is not actually a framebuffer copying driver, it does not create a secondary framebuffer that it would copy bytes across to from the primary framebuffer. It is also no longer a driver only for the ILI9341 controller. A more appropriate name might be userland-raspi-spi-display-driver or something like that, but the original name stuck.
Yes, it does, although not quite as well as on Pi 3B. If you'd like it to run better on a Pi Zero, leave a thumbs up at raspberrypi/userland#440 - hard problems are difficult to justify prioritizing unless it is known that many people care about them.
Edit the file config.h
and comment out the line #define DISPLAY_OUTPUT_LANDSCAPE
. This will make the display output in portrait mode, effectively rotating it by 90 degrees. Note that this only affects the pixel memory reading mode of the display. It is not possible to change the panel scan order to run between landscape and portrait, the SPI displays typically always scan in portrait mode. The result is that it will change the panel vsync tearing mode from "straight line tearing" over to "diagonal tearing" (see the section About Tearing above).
If you do not want to have diagonal tearing, but would prefer straight line tearing, then additionally enable the option #define DISPLAY_FLIP_ORIENTATION_IN_SOFTWARE
in config.h
. That will restore straight line tearing, but it will also increase overall CPU consumption.
Enable the option #define DISPLAY_ROTATE_180_DEGREES
in config.h
. This should rotate the SPI display to show up the other way around, while keeping the HDMI connected display orientation unchanged. Another option is to utilize a /boot/config.txt
option display_rotate=2, which rotates both the SPI output and the HDMI output.
Note that the setting DISPLAY_ROTATE_180_DEGREES
only affects the pixel memory reading mode of the display. It is not possible to flip the panel scan to run inverted by 180 degrees. This means that adjusting these settings will also have effects of changing the visual appearance of the vsync tearing artifact. If you have the ability to mount the display 180 degrees around in your project, it is recommended to do that instead of using the DISPLAY_ROTATE_180_DEGREES
option.
Edit the file config.h
in a text editor (a command line one such as pico
, vim
, nano
, or SSH map the drive to your host), and find the appropriate line in the file. Add comment lines //
in front of that text to disable the option, or remove the //
characters to enable it.
After having edited and saved the file, reissue make -j
in the build directory and restart fbcp-ili9341.
Some options are passed to the build from the CMake configuration script. You can run with make VERBOSE=1
to see which configuration items the CMake build is passing. See the above Configuring Build Options section to customize the CMake configure items. For example, to remove the statistics overlay, pass -DSTATISTICS=0
directive to CMake.
Building requires CMake to be installed on the Pi: try sudo apt-get install cmake
.
Try deleting CMakeCache.txt between changing CMake settings.
Yes, both work fine. For linux command line terminal, the /dev/tty1
console should be set to output to Linux framebuffer 0 ( /dev/fb0
). This is the default mode of operation and there do not exist other framebuffers in a default distribution of Raspbian, but if you have manually messed with the con2fbmap
command in your installation, you may have inadvertently changed this configuration. Run con2fbmap 1
to see which framebuffer the /dev/tty1
console is outputting to, it should print console 1 is mapped to framebuffer 0
. Type con2fbmap 1 0
to reset console 1 back to outputting to framebuffer 0.
Likewise, the X windowing system should be configured to render to framebuffer 0. This is by default the case. The target framebuffer for X windowing service is usually configured via the FRAMEBUFFER
environment variable before launching X. If X is not working by default, you can try overriding the framebuffer by launching X with FRAMEBUFFER=/dev/fb0 startx
instead of just running startx
.
I don't know, I don't currently have any to test. Perhaps the code does need some model specific configuration, or perhaps it might work out of the box. I only have Pi 3B, Pi 3B+, Pi Zero W and a Pi 3 Compute Module based systems to experiment on. Pi 2 B has been reported to work by users (#17).
If the display controller is one of the currently tested ones (see the list above), and it is wired up to run using 4-line SPI, then it should work. Pay attention to configure the Data/Control
GPIO pin number correctly, and also specify the Reset
GPIO pin number if the device has one.
If the display controller is not one of the tested ones, it may still work if it is similar to one of the existing ones. For example, ILI9340 and ILI9341 are practically the same controller. You can just try with a specific one to see how it goes.
If fbcp-ili9341 does not support your display controller, you will have to write support for it. fbcp-ili9341 does not have a "generic SPI TFT driver routine" that might work across multiple devices, but needs specific code for each. If you have the spec sheet available, you can ask for advice, but please do not request to add support to a display controller "blind", that is not possible.
Talvez. This is a more recent experimental feature that may not be as stable, and there are some limitations, but 3-wire ("9-bit") SPI display support is now available. If you have a 3-wire SPI display, ie one that does not have a Data/Control (DC) GPIO pin to connect, configure it via CMake with directive -DGPIO_TFT_DATA_CONTROL=-1
to tell fbcp-ili9341 that it should be driving the display with 3-wire protocol.
Current limitations of 3-wire communication are:
ALL_TASKS_SHOULD_DMA
is currently not supported, there is an issue with DMA chaining that prevents this from being enabled. As result, CPU usage on 3-wire displays will be slightly higher than on 4-wire displays.OFFLOAD_PIXEL_COPY_TO_DMA_CPP
is currently not supported. As a result, 3-wire displays may not work that well on single core Pis like Pi Zero.No. Those are completely different technologies altogether. It should be possible to port the driver algorithm to work on I2C however, if someone is interested.
At the moment one cannot utilize the XPT2046/ADS7846 touch controllers while running fbcp-ili9341, so touch is mutually incompatible with this driver. In order for fbcp-ili9341 to function, you will need to remove all dtoverlay
s in /boot/config.txt
related to touch.
I have done close to everything possible to my displays - cut power in middle of operation, sent random data and command bytes, set their operating voltage commands and clock timings to arbitrary high and low values, tested unspecified and reserved command fields, and driven the displays dozens of MHz faster than they managed to keep up with, and I have not yet done permanent damage to any of my displays or Pis.
Easiest way to do permanent damage is to fail at wiring, eg drive 5 volts if your display requires 3.3v, or short a connection, or something similar.
The one thing that fbcp-ili9341 stays clear off is that it does not program the non-volatile memory areas of any of the displays. Therefore a hard power off on a display should clear all performed initialization and reset the display to its initial state at next power on.
That being said, if it breaks, you'll get to purchase a new shiny one to replace it.
Yes, fbcp-ili9341 shows the output of the HDMI display on the SPI screen, and both can be attached at the same time. A HDMI display does not have to be connected however, although fbcp-ili9341 operation will still be affected by whatever HDMI display mode is configured. Check out tvservice -s
on the command line to check what the current DispmanX HDMI output mode is.
At the moment fbcp-ili9341 has been developed to only display the contents of the main DispmanX GPU framebuffer over to the SPI display. That is, the SPI display will show the same picture as the HDMI output does. There is no technical restriction that requires this though, so if you know C/C++ well, it should be a manageable project to turn fbcp-ili9341 to operate as an offscreen display library to show a completely separate (non-GPU-accelerated) image than what the main HDMI display outputs. For example you could have two different outputs, eg a HUD overlay, a dashboard for network statistics, weather, temps, etc. showing on the SPI while having the main Raspberry Pi desktop on the HDMI.
In this kind of mode, you would probably strip the DispmanX bits out of fbcp-ili9341, and recast it as a static library that you would link to in your drawing application, and instead of snapshotting frames, you can then programmatically write to a framebuffer in memory from your C/C++ code.
Unfortunately there are a number of things to go wrong that all result in a white screen. This is probably the hardest part to diagnose. Some ideas:
This suggests that the power line or the backlight line might not be properly connected. Or if the backlight connects to a GPIO pin on the Pi (and not a voltage pin), then it may be that the pin is not in correct state for the backlight to turn on. Most of the LCD TFT displays I have immediately light up their backlight when they receive power. The Tontec one has a backlight GPIO pin that boots up high but must be pulled low to activate the backlight. OLED displays on the other hand seem to stay all black even after they do get power, while waiting for their initialization to be performed, so for OLEDs it may be normal for nothing to show up on the screen immediately after boot.
If the backlight connects to a GPIO pin, you may need to define -DGPIO_TFT_BACKLIGHT=<pin>
in CMake command line or config.h
, and edit config.h
to enable #define BACKLIGHT_CONTROL
.
fbcp-ili9341 runs a clear screen command at low speed as first thing after init, so if that goes through, it is a good sign. Try increasing -DSPI_BUS_CLOCK_DIVISOR=
CMake option to a higher number to see if the display driving rate was too fast. Or try disabling DMA with -DUSE_DMA_TRANSFERS=OFF
to see if this might be a DMA conflict.
This suggests same as above, increase SPI bus divisor or troubleshoot disabling DMA. If DMA is detected to be the culprit, try changing up the DMA channels. Double check that /boot/config.txt
does not have any dtoverlay
s regarding other SPI display drivers or touch screen controllers, and that it does NOT have a dtparam=spi=on
line in it - fbcp-ili9341 does not use the Linux kernel SPI driver.
Make sure other fbcp
programs are not running, or that another copy of fbcp-ili9341
is not running on the background.
This is likely caused by the program resizing the video resolution at runtime, which breaks DispmanX. See raspberrypi/userland#461 for more details.
Check that the Pi is powered off of a power supply that can keep up with the voltage, and the low voltage icon is not showing up. (remove any avoid_warnings=1/2
directive from /boot/config.txt
if that was used to get rid of warnings overlay, to check that voltage is good) It has been observed that if there is not enough power supplied, the display can be the first to starve, while the Pi might keep on running fine. Try removing turbo settings or lowering the clock speed if you have overclocked to verify that the display crash is not power usage related.
Also try lowering SPI bus speed to a safe lower value, eg half of the maximum speed that the display was able to manage.
Double check the Data/Command (D/C) GPIO pin physically, and in CMake command line. Whenever fbcp-ili9341 refers to pin numbers, they are always specified in BCM pin numbers. Try setting a higher -DSPI_BUS_CLOCK_DIVISOR=
value to CMake. Make sure no other fbcp
programs or SPI drivers or dtoverlays are enabled.
If the color channels are mixed (red is blue, blue is red, green is green) like shown on the left image, pass the CMake option -DDISPLAY_SWAP_BGR=ON
to the build.
If the color intensities look wrong (white is black, black is white, color looks like a negative image) like seen in the middle image, pass the CMake option -DDISPLAY_INVERT_COLORS=ON
to the build.
If the colors looks off in some other fashion, it is possible that the display is just being driven at a too high SPI bus speed, in which case try making the display run slower by choosing a higher -DSPI_BUS_CLOCK_DIVISOR=
option to CMake. Especially on ILI9486 displays it has been observed that the colors on the display can become distorted if the display is run too fast beyond its maximum capability.
fbcp-ili9341 needs a few megabytes of GPU memory to function if DMA transfers are enabled. The gpu_mem boot config option dictates how much of the Pi's memory area is allocated to the GPU. By default this is 64MB, which has been observed to not leave enough memory for fbcp-ili9341 if HDMI is run at 1080p. If this error happens, try increasing GPU memory to eg 128MB by adding a line gpu_mem=128
in /boot/config.txt
.
As the number of supported displays, Raspberry Pi device models, Raspbian/Retropie/Lakka OS versions, accompanied C++ compiler versions and fbcp-ili9341 build options have grown in number, there is a combinatorial explosion of all possible build modes that one can put the codebase through, so it is not easy to keep every possible combo tested all the time. Something may have regressed or gotten outdated. Stay calm, and report a bug.
You can also try looking through the commit history to find changes related to your configuration combo, to see if there's a mention of a known good commit in time that should work for your case. If you get an odd compiler error on cmake
or make
lines, those will usually be very easy to fix, as they are most of the time a result of some configurational oversight.
First, make sure the display is a 4-wire SPI and not a 3-wire one. A display is 4-wire SPI if it has a Data/Control (DC) GPIO line that needs connecting. Sometimes the D/C pin is labeled RS (Register Select). Support for 3-wire SPI displays does exist, but it is experimental and not nearly as well tested as 4-wire displays.
Second is the consideration about display speed. Below is a performance chart of the different displays I have tested. Note that these are sample sizes of one, I don't know how much sample variance there exists. Also I don't know if it is likely that there exists big differences between displays with same controller from different manufacturers. At least the different ILI9341 displays that I have are all quite consistent on performance, whether they are from Adafruit or WaveShare or from BuyDisplay.com.
Vendor | Tamanho | Resolução | Controlador | Rated SPI Bus Speed | Obtained Bus Speed | Taxa de quadros |
---|---|---|---|---|---|---|
Adafruit PiTFT | 2.8" | 240x320 | ILI9341 | 10MHz | 294MHz/4=73.50MHz | 59.81 fps |
Adafruit PiTFT | 2.2" | 240x320 | ILI9340 | 15.15MHz | 338MHz/4=84.50MHz | 68.76 fps |
Adafruit PiTFT | 3.5" | 320x480 | HX8357D | 15.15MHz | 314MHz/6=52.33MHz | 21.29 fps |
Adafruit OLED | 1.27" | 128x96 | SSD1351 | 20MHz | 360MHz/20=18.00MHz | 91.55 fps |
Waveshare RPi LCD (B) IPS | 3.5" | 320x480 | ILI9486 | 15.15MHz | 255MHz/8=31.88MHz | 12.97 fps |
maithoga TFT LCD | 3.5" | 320x480 | ILI9486L | 15.15MHz | 400MHz/8=50.00MHz | 13.56 fps* |
BuyDisplay.com SPI TFT copy #1 | 3.2" | 240x320 | ILI9341 | 10MHz | 310MHz/4=77.50MHz | 63.07 fps |
BuyDisplay.com SPI TFT copy #2 | 3.2" | 240x320 | ILI9341 | 10MHz | 300MHz/4=75.00MHz | 61.03 fps |
Arduino A000096 LCD | 1.77" | 128x160 | ST7735R | 15.15MHz | 355MHz/6=59.16MHz | 180.56 fps |
Tontec MZ61581-PI-EXT 2016.1.28 | 3.5" | 320x480 | MZ61581 | 128MHz | 280MHz/2=140.00MHz | 56.97 fps |
Adafruit 240x240 Wide Angle TFT | 1.54" | 240x240 | ST7789 | ? | 340MHz/4=85.00MHz | 92.23 fps |
WaveShare 240x240 Display HAT | 1.3" | 240x240 | ST7789VW | 62.5MHz | 338MHz/4=84.50MHz | 91.69 fps |
WaveShare 128x128 Display HAT | 1.44" | 128x128 | ST7735S | 15.15MHz | (untested) | (untested) |
KeDei v6.3 | 3.5" | 320x480 | MPI3501 | ? | 400MHz/12=33.333MHz | 4.8fps ** |
In this list, Rated SPI Bus Speed is the maximum clock speed that the display controller is rated to run at. The Obtained Bus Speed column lists the fastest SPI bus speed that was achieved in practice, and the core_freq
BCM Core speed and SPI Clock Divider CDIV
setting that was used to achieve that rate. Note how most display controllers can generally be driven much faster than what they are officially rated at in their spec sheets.
The Frame Rate column shows the worst case frame rate when full screen updates are being performed. This occurs for example when watching fullscreen video (that is not a flat colored cartoon). Because fbcp-ili9341 only sends over the pixels that have changed, displays such as HX8357D and ILI9486 can still be used to play many games at 60fps. Retro games work especially well.
All the ILI9341 displays work nice and super fast at ~70-80MHz. My WaveShare 3.5" 320x480 ILI9486 display runs really slow compared to its pixel resolution, ~32MHz only. See fbcp-ili9341 ported to ILI9486 WaveShare 3.5" (B) SpotPear 320x480 SPI display for a video of this display in action. Adafruit's 320x480 3.5" HX8357D PiTFTs is ~64% faster in comparison.
The ILI9486L controller based maithoga display runs a bit faster than ILI9486 WaveShare, 50MHz versus 31.88MHz, ie +56.8% bandwidth increase. However fps-wise maithoga reaches only 13.56 vs WaveShare 12.97 fps, because the bandwidth advantage is fully lost in pixel format differences: ILI9486L requires transmitting 24 bits per each pixel (R6G6B6 mode), whereas ILI9486 supports 16 bits per pixel R5G6B5 mode. This is reflected in the above chart refresh rate for the maithoga display (marked with a star).
If manufacturing variances turn out not to be high between copies, and you'd like to have a bigger 320x480 display instead of a 240x320 one, then it is recommended to avoid ILI9486, they indeed are slow.
The KeDei v6.3 display with MPI3501 controller takes the crown of being horrible, in all aspects imaginable. It is able to run at 33.33 MHz, but due to technical design limitations of the display (see #40), effective bus speed is halved, and only about 72% utilization of the remaining bus rate is achieved. DMA cannot be used, so CPU usage will be off the charts. Even though fbcp-ili9341 supports this display, level of support is expected to be poor, because the hardware design is a closed secret without open documentation publicly available from the manufacturer. Stay clear of KeDei or MPI3501 displays.
The Tontec MZ61581 controller based 320x480 3.5" display on the other hand can be driven insanely fast at up to 140MHz! These seem to be quite hard to come by though and they are expensive. Tontec seems to have gone out of business and for example the domain itontec.com from which the supplied instructions sheet asks to download original drivers from is no longer registered. I was able to find one from eBay for testing.
Search around, or ask the manufacturer of the display what the maximum SPI bus speed is for the device. This is the most important aspect to getting good frame rates, but unfortunately most web links never state the SPI speed rating, or they state it ridiculously low like in the spec sheets. Try and buy to see, or ask in some community forums from people who already have a particular display to find out what SPI bus speed it can achieve.
One might think that since Pi Zero is slower than a Pi 3, the SPI bus speed might not matter as much when running on a Pi Zero, but the effect is rather the opposite. To get good framerates on a Pi Zero, it should be paired with a display with as high SPI bus speed capability as possible. This is because the higher the SPI bus speed is, the more autonomously a DMA controller can drive it without CPU intervention. For the same reason, the interlacing technique does not (currently at least) perform well on a Pi Zero, so it is disabled there by default. ILI9341s run well on Pi Zero, ILI9486 on the other hand is quite difficult to combine with a Pi Zero.
Ultimately, it should be noted that parallel displays (DPI) are the proper method for getting fast framerates easily. SPI displays should only be preferred if display form factor is important and a desired product might only exist as SPI and not as DPI, or the number of GPIO pins that are available on the Pi is scarce that sacrificing dozens of pins to RGB data is not viável.
Hardware-wise, there are six different ways to connect displays to the Pi. Here are the pros and cons of each:
Displays are generally manufactured to utilize one specific interfacing method, with the exception that some displays have a both I²C and SPI modes that can be configured via soldering.
Fbcp-ili9341 driver is about interfacing with SPI displays. If your display utilizes some other connection mechanism, fbcp-ili9341 will not apply.
Software-wise, there are two possible alternatives to fbcp-ili9341:
The following links proved helpful when writing this:
If you would like to help push Raspberry Pi SPI display support further, there are always more things to do in the project. Here is a list of ideas and TODOs for recognized work items to contribute, roughly rated in order of increasing difficulty.
top
/ htop
, or with a power meter off the wall and report the results.SPI_3WIRE_PROTOCOL
+ ALL_TASKS_SHOULD_DMA
to work together, or 3) fix up SPI_3WIRE_PROTOCOL
+ OFFLOAD_PIXEL_COPY_TO_DMA_CPP
to work together.ALL_TASKS_SHOULD_DMA
mode to be always superior in performance and CPU usage so that the non- ALL_TASKS_SHOULD_DMA
path can be dropped from the codebase. (probably requires the above chaining to function efficiently)This driver is licensed under the MIT License. See LICENSE.txt. In nonlegal terms, it's yours for both free and commercial projects, DIY packages, kickstarters, Etsys and Ebays, and you don't owe back a dime. Feel free to apply and derive as you wish.
If you found fbcp-ili9341 useful, it makes me happy to hear back about the projects it found a home in. If you did a build or a project where fbcp-ili9341 worked out, it'd be great to see a video or some photos or read about your experiences.
I hope you build something you enjoy!
Best way to discuss the driver is to open a GitHub issue. You may also be able to find me over at sudomod.com Discord channel.