Skip to content

Commit

Permalink
u8g2 stm32l0 dma example
Browse files Browse the repository at this point in the history
  • Loading branch information
olikraus committed Jan 8, 2025
1 parent a0eb1ba commit 4fa7835
Show file tree
Hide file tree
Showing 2 changed files with 115 additions and 45 deletions.
47 changes: 4 additions & 43 deletions sys/arm/stm32l031x4/u8g2_test/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ uint8_t u8x8_gpio_and_delay_stm32l0_sw_i2c(u8x8_t *u8x8, uint8_t msg, uint8_t ar
uint8_t u8x8_gpio_and_delay_stm32l0_spi(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);

uint8_t u8x8_byte_stm32l0_hw_spi(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
uint8_t u8x8_byte_stm32l0_dma_spi(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);


/*=======================================================================*/
Expand Down Expand Up @@ -118,7 +119,9 @@ void initDisplay(void)

//u8g2_Setup_uc1609_slg19264_f(&u8g2, U8G2_R2, u8x8_byte_4wire_sw_spi, u8x8_gpio_and_delay_stm32l0_spi);

u8g2_Setup_uc1609_slg19264_f(&u8g2, U8G2_R2, u8x8_byte_stm32l0_hw_spi, u8x8_gpio_and_delay_stm32l0_spi);
// u8g2_Setup_uc1609_slg19264_f(&u8g2, U8G2_R2, u8x8_byte_stm32l0_hw_spi, u8x8_gpio_and_delay_stm32l0_spi);

u8g2_Setup_uc1609_slg19264_f(&u8g2, U8G2_R2, u8x8_byte_stm32l0_dma_spi, u8x8_gpio_and_delay_stm32l0_spi);


u8g2_InitDisplay(&u8g2);
Expand Down Expand Up @@ -176,49 +179,8 @@ void setRow(uint8_t r)
u8g2_y = r;
}

void notused(void *ptr, uint16_t cnt)
{
/* disable and reset to defaults */
DMA1_Channel1->CCR = 0;

/* defaults:
- 8 Bit access --> will be changed below
- read from peripheral --> ok
- none-circular mode --> ok
- no increment mode --> will be changed below
*/


DMA1_Channel1->CNDTR = cnt; /* buffer size */
DMA1_Channel1->CPAR = (uint32_t)&(ADC1->DR); /* source value */
// DMA1_Channel1->CPAR = (uint32_t)&(GPIOA->ODR); /* source value */
DMA1_Channel1->CMAR = (uint32_t)ptr; /* destination memory */

DMA1_CSELR->CSELR &= ~DMA_CSELR_C1S; /* 0000: select ADC for DMA CH 1 (this is reset default) */
DMA1_CSELR->CSELR &= ~DMA_CSELR_C2S; /* 0000: select ADC for DMA CH 2 (this is reset default) */

DMA1_Channel1->CCR |= DMA_CCR_MINC; /* increment memory */
DMA1_Channel1->CCR |= DMA_CCR_MSIZE_0; /* 01: 16 Bit access */
DMA1_Channel1->CCR |= DMA_CCR_PSIZE_0; /* 01: 16 Bit access */

DMA1_Channel1->CCR |= DMA_CCR_EN; /* enable */


/*
detect rising edge on external trigger (ADC_CFGR1_EXTEN_0)
recive trigger from TIM2 (ADC_CFGR1_EXTSEL_1)
8 Bit resolution (ADC_CFGR1_RES_1)
Use DMA one shot mode and enable DMA (ADC_CFGR1_DMAEN)
Once DMA is finished, it will disable continues mode (ADC_CFGR1_CONT)
*/


}

/*=======================================================================*/


int main()
{
uint8_t v = 0;
Expand All @@ -236,7 +198,6 @@ int main()
GPIOA->BSRR = GPIO_BSRR_BR_9; /* atomic clear */



for(;;)
{
GPIOA->BSRR = GPIO_BSRR_BR_9; /* atomic clear */
Expand Down
113 changes: 111 additions & 2 deletions sys/arm/stm32l031x4/u8g2_test/u8x8cb.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include "stm32l031xx.h"
#include "delay.h"
#include "u8x8.h"
#include <string.h> /* memcpy */

/*
I2C:
Expand Down Expand Up @@ -279,6 +280,7 @@ uint8_t u8x8_byte_stm32l0_hw_spi(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, voi
/* setup and enable SPI subsystem */
/* Note: We assume SPI mode 0 for the displays (true for the most modern displays), so CPHA and CPOL are forced to 0 here. SPI mode is here: u8x8->display_info->spi_mode */

/* Note: The below assignment will setup also the clock speed, which in turn depends on the uC master clock */
SPI1->CR1 = SPI_CR1_MSTR // master
//| SPI_CR1_BIDIMODE
//| SPI_CR1_BIDIOE
Expand All @@ -291,8 +293,7 @@ uint8_t u8x8_byte_stm32l0_hw_spi(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, voi
//| SPI_CR1_CPOL
;
SPI1->CR2 = 0; // SPI_CR2_TXDMAEN = transmit DMA enable
SPI1->CR1 |= SPI_CR1_SPE; // SPI enable

SPI1->CR1 |= SPI_CR1_SPE; // SPI enable
u8x8_gpio_SetCS(u8x8, u8x8->display_info->chip_disable_level);
break;
case U8X8_MSG_BYTE_SET_DC:
Expand All @@ -315,3 +316,111 @@ uint8_t u8x8_byte_stm32l0_hw_spi(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, voi
}
return 1;
}


uint8_t dma_buffer[256]; // required for DMA transfer

uint8_t u8x8_byte_stm32l0_dma_spi(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
{
//uint8_t *data;
switch(msg) {
case U8X8_MSG_BYTE_SEND:
/* data in arg_ptr will be overwritten, once we leave this function, so create a copy of it */
memcpy(dma_buffer, arg_ptr, arg_int);

/* wait for completion of any previous transfer */
while ( (SPI1->SR & SPI_SR_BSY) || (DMA1_Channel3->CNDTR != 0) ) // wait for transfer completion
;

/* setup and start DMA SPI transfer */
DMA1_Channel3->CCR = 0; // disable + reset channel 3
/* defaults:
- 8 Bit access --> ok
- read from peripheral --> changed
- none-circular mode --> ok
- no increment mode --> will be changed below
*/
DMA1_Channel3->CNDTR = arg_int; /* buffer size */
DMA1_Channel3->CMAR = (uint32_t)dma_buffer;
DMA1_Channel3->CPAR = (uint32_t)&(SPI1->DR);

DMA1_Channel3->CCR |= DMA_CCR_MINC | DMA_CCR_DIR; /* increment memory, copy from M to P */
DMA1_Channel3->CCR |= DMA_CCR_EN; /* enable */

/*
data = (uint8_t *)arg_ptr;
while( arg_int > 0 )
{
while( ( SPI1->SR & SPI_SR_TXE ) == 0 )
;
*(uint8_t *)&(SPI1->DR) = *data;
data++;
arg_int--;
}
*/
break;
case U8X8_MSG_BYTE_INIT:
/* enable clock for SPI and DMA*/
RCC->APB2ENR |= RCC_APB2ENR_SPI1EN; /* enable SPI1 */
RCC->AHBENR |= RCC_AHBENR_DMA1EN;
/* set a predivision if the system clock is too high, not required for 2MHz */
RCC->CFGR &= ~RCC_CFGR_PPRE2_Msk;
//RCC->CFGR |= RCC_CFGR_PPRE2_DIV4;

/* output setup is already done, just enable the alternate mode here */

GPIOA->MODER &= ~GPIO_MODER_MODE7; /* clear mode */
GPIOA->MODER |= GPIO_MODER_MODE7_1; /* Alternate function mode */
GPIOA->AFR[0] &= ~GPIO_AFRL_AFRL7_Msk; /* clear af mode */
GPIOA->AFR[0] |= 0 << GPIO_AFRL_AFRL7_Pos; /* assign af mode (which is 0 for SPI) */

GPIOA->MODER &= ~GPIO_MODER_MODE5; /* clear mode */
GPIOA->MODER |= GPIO_MODER_MODE5_1; /* Alternate function mode */
GPIOA->AFR[0] &= ~GPIO_AFRL_AFRL5_Msk; /* clear af mode */
GPIOA->AFR[0] |= 0 << GPIO_AFRL_AFRL5_Pos; /* assign af mode (which is 0 for SPI) */


DMA1_CSELR->CSELR &= ~DMA_CSELR_C3S_Msk; /* clear selection on Channel 3 */
DMA1_CSELR->CSELR |= 1 << DMA_CSELR_C3S_Pos; /* aktivate SPI_TX on Channel 3 */
DMA1_Channel3->CCR = 0; // disable + reset channel 3
DMA1_Channel3->CNDTR = 0; /* clear buffer size */

/* setup and enable SPI subsystem */
/* Note: We assume SPI mode 0 for the displays (true for the most modern displays), so CPHA and CPOL are forced to 0 here. SPI mode is here: u8x8->display_info->spi_mode */

/* Note: The below assignment will setup also the clock speed, which in turn depends on the uC master clock */
SPI1->CR1 = SPI_CR1_MSTR // master
//| SPI_CR1_BIDIMODE
//| SPI_CR1_BIDIOE
| SPI_CR1_SSM
| SPI_CR1_SSI
//| SPI_CR1_BR_0
//| SPI_CR1_BR_1
//| SPI_CR1_BR_2 // speed
//| SPI_CR1_CPHA
//| SPI_CR1_CPOL
;
SPI1->CR2 = SPI_CR2_TXDMAEN; // SPI_CR2_TXDMAEN = transmit DMA enable
SPI1->CR1 |= SPI_CR1_SPE; // SPI enable
u8x8_gpio_SetCS(u8x8, u8x8->display_info->chip_disable_level);
break;
case U8X8_MSG_BYTE_SET_DC:
while ( (SPI1->SR & SPI_SR_BSY) || (DMA1_Channel3->CNDTR != 0) ) // wait for transfer completion
;
u8x8_gpio_SetDC(u8x8, arg_int);
break;
case U8X8_MSG_BYTE_START_TRANSFER:
u8x8_gpio_SetCS(u8x8, u8x8->display_info->chip_enable_level);
u8x8->gpio_and_delay_cb(u8x8, U8X8_MSG_DELAY_NANO, u8x8->display_info->post_chip_enable_wait_ns, NULL);
break;
case U8X8_MSG_BYTE_END_TRANSFER:
while ( (SPI1->SR & SPI_SR_BSY) || (DMA1_Channel3->CNDTR != 0) ) // wait for transfer completion
;
u8x8->gpio_and_delay_cb(u8x8, U8X8_MSG_DELAY_NANO, u8x8->display_info->pre_chip_disable_wait_ns, NULL);
u8x8_gpio_SetCS(u8x8, u8x8->display_info->chip_disable_level);
break;
default:
return 0;
}
return 1;
}

0 comments on commit 4fa7835

Please sign in to comment.