Radix cross Linux

The main Radix cross Linux repository contains the build scripts of packages, which have the most complete and common functionality for desktop machines

452 Commits   2 Branches   1 Tag
Index: Makefile
===================================================================
--- Makefile	(nonexistent)
+++ Makefile	(revision 411)
@@ -0,0 +1,43 @@
+
+# GD32VF103 Linker Script:
+LDFLAGS += -T../device/gd32vf103xb.ld
+
+# Source files:
+AS_SRC  = ../device/gd32vf103xb_boot.S
+C_SRC   = main.c
+C_SRC  += ../device/n200_func.c
+
+# Header file directories:
+INCLUDE = -I../device/include
+
+# Object files to build:
+OBJS  = $(AS_SRC:.S=.o)
+OBJS += $(C_SRC:.c=.o)
+
+# Default rule to build the whole project:
+.PHONY: all
+all: main.bin
+
+# Rule to build assembly files:
+%.o: %.S
+	$(CC) -x assembler-with-cpp -c $(CFLAGS) $(INCLUDE) $< -o $@
+
+# Rule to compile C files:
+%.o: %.c
+	$(CC) -c $(CFLAGS) $(INCLUDE) $< -o $@
+
+# Rule to create an ELF file from the compiled object files:
+main.elf: $(OBJS)
+	$(CC) $^ $(LDFLAGS) -o $@
+
+# Rule to create a raw binary file from an ELF file:
+main.bin: main.elf
+	$(OBJCOPY) -S -O binary $< $@
+	$(SIZE) $<
+
+# Rule to clear out generated build files:
+.PHONY: clean
+clean:
+	rm -f $(OBJS)
+	rm -f main.elf
+	rm -f main.bin
Index: main.c
===================================================================
--- main.c	(nonexistent)
+++ main.c	(revision 411)
@@ -0,0 +1,293 @@
+
+#include <stdint.h>
+#include <string.h>
+
+#include <gd32vf103.h>
+#include <n200_func.h>
+#include <riscv_encoding.h>
+
+/*
+  Uncomment this line if you have only -march=rv32imac instead of -march=rv32imac_zicsr:
+__asm("\t.option arch, +zicsr");
+ */
+
+/* Pre-defined memory locations for program initialization */
+extern uint32_t _sidata, _sdata, _edata, _sbss, _ebss;
+/* Current system core clock speed */
+volatile uint32_t SystemCoreClock = 8000000;
+/* Global 'tick' value */
+volatile uint32_t systick = 0;
+/* Framebuffer for the TFT display */
+#define TFT_W ( 160 )
+#define TFT_H ( 80 )
+#define TFT_A ( TFT_W * TFT_H )
+volatile uint16_t fb[ TFT_A ];
+
+/* Simple "millisecond delay" function */
+void delay_ms( uint32_t ms ) {
+  /* Calculate the 'system tick' value to wait until */
+  uint32_t done = systick + ms;
+  /* Wait until the 'systick' value ticks up enough */
+  while ( systick < done ) { __WFI(); }
+}
+
+/* 'Switch mode' display helper function */
+#define MODE_CMD ( 0 )
+#define MODE_DAT ( 1 )
+void display_mode( int type ) {
+  /* Wait for any ongoing transfers to finish */
+  while ( SPI1->SR & SPI_SR_BSY ) {};
+  /* Set the 'data / command' pin level */
+  if ( type ) { GPIOB->ODR |=  ( 0x1 << 0 ); }
+  else        { GPIOB->ODR &= ~( 0x1 << 0 ); }
+}
+
+/* 'Write SPI byte' display helper function */
+void spi_w8( SPI_TypeDef* SPIx, uint8_t byte ) {
+  /* Wait for the transmit buffer to have space */
+  while ( !( SPI1->SR & SPI_SR_TXE ) ) {};
+  /* Send the next byte of data */
+  *( uint8_t * )&( SPIx->DR ) = byte;
+}
+
+/* 'Write SPI half-word' display helper function */
+void spi_w16( SPI_TypeDef* SPIx, uint16_t hword ) {
+  spi_w8( SPIx, hword >> 8 );
+  spi_w8( SPIx, hword & 0xFF );
+}
+
+/* 'main' method which gets called from the boot code */
+int main( void ) {
+  /* Copy initialized data from .sidata (Flash) to .data (RAM) */
+  memcpy( &_sdata, &_sidata, ( ( void* )&_edata - ( void* )&_sdata ) );
+  /* Clear the .bss RAM section */
+  memset( &_sbss, 0x00, ( ( void* )&_ebss - ( void* )&_sbss ) );
+
+  /* Reset the SPI1 peripheral */
+  RCC->APB2RSTR |=  ( RCC_APB2RSTR_SPI1RST );
+  RCC->APB2RSTR &= ~( RCC_APB2RSTR_SPI1RST );
+  /* Clear the DMA channel 3 configuration */
+  DMA1_Channel3->CCR = 0x00000000;
+  /* Enable the GPIOA, GPIOB, GPIOC, SPI1, and DMA1 peripherals */
+  RCC->APB2ENR  |=  ( RCC_APB2ENR_IOPAEN |
+                      RCC_APB2ENR_IOPBEN |
+                      RCC_APB2ENR_IOPCEN |
+                      RCC_APB2ENR_SPI1EN );
+  RCC->AHBENR   |=  ( RCC_AHBENR_DMA1EN );
+
+  /* Configure pins A1, A2, and C13 as low-speed push-pull outputs */
+  GPIOA->CRL   &= ~( GPIO_CRL_MODE1 | GPIO_CRL_CNF1 |
+                     GPIO_CRL_MODE2 | GPIO_CRL_CNF2 );
+  GPIOA->CRL   |=  ( ( 0x2 << GPIO_CRL_MODE1_Pos ) |
+                     ( 0x2 << GPIO_CRL_MODE2_Pos ) );
+  GPIOC->CRH   &= ~( GPIO_CRH_MODE13 | GPIO_CRH_CNF13 );
+  GPIOC->CRH   |=  ( 0x2 << GPIO_CRH_MODE13_Pos );
+  /* Configure pins A5 and A7 as high-speed alternate-function outputs */
+  GPIOA->CRL   &= ~( GPIO_CRL_MODE5 | GPIO_CRL_CNF5 |
+                     GPIO_CRL_MODE7 | GPIO_CRL_CNF7 );
+  GPIOA->CRL   |=  ( ( 0x3 << GPIO_CRL_MODE5_Pos ) |
+                     ( 0x3 << GPIO_CRL_MODE7_Pos ) |
+                     ( 0x2 << GPIO_CRL_CNF5_Pos ) |
+                     ( 0x2 << GPIO_CRL_CNF7_Pos ) );
+  /* Configure pins B0, B1, and B2 as low-speed push-pull outputs */
+  GPIOB->CRL   &= ~( ( GPIO_CRL_MODE0 | GPIO_CRL_CNF0 ) |
+                     ( GPIO_CRL_MODE1 | GPIO_CRL_CNF1 ) |
+                     ( GPIO_CRL_MODE2 | GPIO_CRL_CNF2 ) );
+  GPIOB->CRL   |=  ( ( 0x2 << GPIO_CRL_MODE0_Pos ) |
+                     ( 0x2 << GPIO_CRL_MODE1_Pos ) |
+                     ( 0x2 << GPIO_CRL_MODE2_Pos ) );
+
+  /*
+    Turn the green LED off, and the red/blue LEDs on.
+    The pins are connected to the LED cathodes, so pulling
+    the pin high turns the LED off, and low turns it on.
+   */
+  GPIOA->ODR   |=  ( 0x1 << 1 );
+  GPIOA->ODR   &= ~( 0x1 << 2 );
+  GPIOC->ODR   &= ~( 0x1 << 13 );
+
+  /*
+    DMA configuration:
+     - Memory-to-peripheral mode.
+     - Circular mode enabled for continuous transfer.
+     - Increment source ptr, don't increment destination ptr.
+     - 8-bit transfer length.
+     - High-priority. Not that priority matters; it's the only one.
+   */
+  DMA1_Channel3->CCR  &= ~( DMA_CCR_MEM2MEM |
+                            DMA_CCR_PL |
+                            DMA_CCR_MSIZE |
+                            DMA_CCR_PSIZE |
+                            DMA_CCR_PINC |
+                            DMA_CCR_EN );
+  DMA1_Channel3->CCR  |=  ( ( 0x2 << DMA_CCR_PL_Pos ) |
+                            DMA_CCR_MINC |
+                            DMA_CCR_CIRC |
+                            DMA_CCR_DIR );
+  /* Set source memory address to the framebuffer array */
+  DMA1_Channel3->CMAR  =  ( uint32_t )&( fb );
+  /* Set destination peripheral address to the SPI1 data register */
+  DMA1_Channel3->CPAR  =  ( uint32_t )&( SPI1->DR );
+  /* Set the number of bits to transfer. In this case, it's the
+     number of 16-bit colors multiplied by two.
+   */
+  DMA1_Channel3->CNDTR =  ( uint32_t )( TFT_A * 2 );
+
+  /*
+    SPI1 setup: host mode, no baud rate division, sw cs pin control,
+    TX DMA enabled, 8-bit frames, msb-first, enable the peripheral.
+    Some of those settings are the default state after a reset.
+   */
+  SPI1->CR2  |=  ( SPI_CR2_TXDMAEN );
+  SPI1->CR1  &= ~( SPI_CR1_BR );
+  SPI1->CR1  |=  ( SPI_CR1_SSM |
+                   SPI_CR1_SSI |
+                   SPI_CR1_MSTR |
+                   SPI_CR1_SPE );
+
+  /* Set up the global timer to generate an interrupt every ms */
+  /* Figure out how many interrupts are available */
+  uint32_t max_irqn = *( volatile uint32_t * )( ECLIC_ADDR_BASE + ECLIC_INFO_OFFSET );
+  max_irqn &= ( 0x00001FFF );
+  /* Initialize the 'ECLIC' interrupt controller */
+  eclic_init( max_irqn );
+  eclic_mode_enable();
+  /* Set 'vector mode' so the timer interrupt uses the vector table */
+  eclic_set_vmode( CLIC_INT_TMR );
+  /* Enable the timer interrupt (#7) with low priority and 'level' */
+  eclic_enable_interrupt( CLIC_INT_TMR );
+  eclic_set_irq_lvl_abs( CLIC_INT_TMR, 1 );
+  eclic_set_irq_priority( CLIC_INT_TMR, 1 );
+  /* Set the timer's comparison value to (frequency / 1000) */
+  *( volatile uint64_t * )( TIMER_CTRL_ADDR + TIMER_MTIMECMP ) = ( TIMER_FREQ / 1000 );
+  /* Reset the timer value to zero */
+  *( volatile uint64_t * )( TIMER_CTRL_ADDR + TIMER_MTIME ) = 0;
+  /* Re-enable interrupts globally */
+  set_csr( mstatus, MSTATUS_MIE );
+
+  /* Set initial SPI pin positions */
+  /* Pull the 'chip select' pin high to de-select the display */
+  GPIOB->ODR |=  ( 0x1 << 2 );
+  /* Pull the 'reset' pin low to reset the display */
+  GPIOB->ODR &= ~( 0x1 << 1 );
+  /* Wait 100ms and pull the 'reset' pin high */
+  delay_ms( 100 );
+  GPIOB->ODR |=  ( 0x1 << 1 );
+  /* Pull the 'chip select' pin low to get the display's attention */
+  GPIOB->ODR &= ~( 0x1 << 2 );
+
+  /******************************************************************
+    Send initialization commands to the display before starting DMA.
+    Software reset.
+   */
+  display_mode( MODE_CMD );
+  spi_w8( SPI1, 0x01 );
+  delay_ms( 100 );
+  /* Display off */
+  spi_w8( SPI1, 0x28 );
+  /* 'Inverted' color mode, so that 0 is 'off' and 1 is 'on': */
+  spi_w8( SPI1, 0x21 );
+  /* Color mode: 16bpp */
+  spi_w8( SPI1, 0x3A );
+  display_mode( MODE_DAT );
+  spi_w8( SPI1, 0x05 );
+  /* Memory access control */
+  display_mode( MODE_CMD );
+  spi_w8( SPI1, 0x36 );
+  display_mode( MODE_DAT );
+  spi_w8( SPI1, 0x20 );
+  /* Exit sleep mode */
+  display_mode( MODE_CMD );
+  spi_w8( SPI1, 0x11 );
+  delay_ms( 100 );
+  /* Display on */
+  spi_w8( SPI1, 0x29 );
+  delay_ms( 100 );
+  /* Set drawing window */
+  /* Column set */
+  spi_w8( SPI1, 0x2A );
+  display_mode( MODE_DAT );
+  spi_w16( SPI1, 1 );
+  spi_w16( SPI1, TFT_W );
+  /* Row set */
+  display_mode( MODE_CMD );
+  spi_w8( SPI1, 0x2B );
+  display_mode( MODE_DAT );
+  spi_w16( SPI1, 26 );
+  spi_w16( SPI1, TFT_H + 25 );
+  /* Set 'write to RAM' mode */
+  display_mode( MODE_CMD );
+  spi_w8( SPI1, 0x2C );
+  /* Set 'data' transfer mode to start sending pixel data */
+  display_mode( MODE_DAT );
+
+  /* Set 'LSBFIRST' mode to make it easier to set color values */
+  SPI1->CR1          |=  ( SPI_CR1_LSBFIRST );
+  /* Enable the circular DMA transfer */
+  DMA1_Channel3->CCR |=  ( DMA_CCR_EN );
+
+  /**************************************************
+    Cycle the display through a few patterns.
+    For now, just solid colors, and set the on-board
+    LED to the current display color.
+   */
+  #define PATTERN_DELAY ( 1000 )
+  while( 1 ) {
+    /*
+      TODO:
+        Less code re-use. Also, the DMA transfer seems to send
+        each byte 'backwards', so the raw hex values are a little
+        tricky to figure out. Maybe seeting `LSBFIRST` could help?
+        Red (5 most-significant bits)
+     */
+    for ( uint32_t i = 0; i < TFT_A; ++i ) {
+      fb[ i ] = 0xF800;
+    }
+    GPIOA->ODR |=  ( 0x1 << 1 |
+                     0x1 << 2 );
+    GPIOC->ODR &= ~( 0x1 << 13 );
+    delay_ms( PATTERN_DELAY );
+    /* Yellow */
+    for ( uint32_t i = 0; i < TFT_A; ++i ) {
+      fb[ i ] = 0xFFE0;
+    }
+    GPIOA->ODR &= ~( 0x1 << 1 );
+    GPIOA->ODR |=  ( 0x1 << 2 );
+    GPIOC->ODR &= ~( 0x1 << 13 );
+    delay_ms( PATTERN_DELAY );
+    /* Green (6 middle bits) */
+    for ( uint32_t i = 0; i < TFT_A; ++i ) {
+      fb[ i ] = 0x03E0;
+    }
+    GPIOA->ODR &= ~( 0x1 << 1 );
+    GPIOA->ODR |=  ( 0x1 << 2 );
+    GPIOC->ODR |=  ( 0x1 << 13 );
+    delay_ms( PATTERN_DELAY );
+    /* Purple */
+    for ( uint32_t i = 0; i < TFT_A; ++i ) {
+      fb[ i ] = 0xF81F;
+    }
+    GPIOA->ODR |=  ( 0x1 << 1 );
+    GPIOA->ODR &= ~( 0x1 << 2 );
+    GPIOC->ODR &= ~( 0x1 << 13 );
+    delay_ms( PATTERN_DELAY );
+    /* Blue (5 least-significant bits) */
+    for ( uint32_t i = 0; i < TFT_A; ++i ) {
+      fb[ i ] = 0x001F;
+    }
+    GPIOA->ODR |=  ( 0x1 << 1 );
+    GPIOA->ODR &= ~( 0x1 << 2 );
+    GPIOC->ODR |=  ( 0x1 << 13 );
+    delay_ms( PATTERN_DELAY );
+  }
+  return 0;
+}
+
+/* System timer interrupt */
+__attribute__( ( interrupt ) )
+void eclic_mtip_handler( void ) {
+  /* Increment the global 'tick' value */
+  systick++;
+  /* Reset the 'mtime' value to zero */
+  *( volatile uint64_t * )( TIMER_CTRL_ADDR + TIMER_MTIME ) = 0;
+}