Compare commits

...

3 Commits

Author SHA1 Message Date
Ondrej Hladuvka 18a89741e0 project 2025-06-03 11:46:39 +03:00
Ondrej Hladuvka 7ef60597e4 Merge branch 'main' into dev 2025-06-01 17:43:38 +03:00
AntonJ 83189c41da Project added for completion 2025-05-16 18:26:59 +03:00
5 changed files with 426 additions and 6 deletions

View File

@ -3,15 +3,12 @@
#include "inc/msp432p401r.h"
void BumpInit(void) {
// Port 4 pins 0, 2, 3, 5, 6, 7
// and enables internal resistors
P4->SEL0 &= ~BUMP_PINS;
P4->SEL1 &= ~BUMP_PINS; // 1) configure P4.0 P4.2 P4.3 P4.5 P4.6 P4.7 as gpio
P4->DIR &= ~BUMP_PINS; // 2) configure as input
P4->REN |= BUMP_PINS; // 3) enable pull resisors
P4->SEL1 &= ~BUMP_PINS; // configure P4.0 P4.2 P4.3 P4.5 P4.6 P4.7 as gpio
P4->DIR &= ~BUMP_PINS; // configure as input
P4->REN |= BUMP_PINS; // enable pull resisors
}
uint8_t BumpRead(void) {
// write this as part of Lab 2
return P4->IN;
}

191
common/rtos.c Normal file
View File

@ -0,0 +1,191 @@
#include <stdlib.h>
#include "rtos.h"
#include "clock.h"
#include "cpu.h"
#include "timer_a1.h"
#include "inc/msp432p401r.h"
#define THREADS 2
#define PERIODIC_THREADS 2
#define STACKSIZE 100
typedef struct Tcb {
int32_t* sp; // stack pointer
struct Tcb* next; // linked-list
int32_t* blocked; // shows on which semaphore it is blocked
int32_t sleep;
} Tcb_t;
PeriodicEvent_t periodic_event_threads[PERIODIC_THREADS];
Tcb_t tcbs[THREADS];
Tcb_t* run_pt;
int32_t stacks[THREADS][STACKSIZE];
void RunPeriodicEvents(void);
void __attribute__((naked)) SysTick_Handler(void) {
__asm volatile (
"CPSID I \n" // disable interrupts
"PUSH {R4-R11} \n" // save R4-R11
"LDR R0, =run_pt \n" // R0 = pointer to run_pt
"LDR R1, [R0] \n" // R1 = run_pt
"STR SP, [R1] \n" // save current SP
"PUSH {R0, LR} \n" // save R0, LR
"BL Scheduler \n" // call scheduler
"POP {R0, LR} \n" // restore R0, LR
"LDR R1, [R0] \n" // R1 = run_pt
"LDR SP, [R1] \n" // restore new SP
"POP {R4-R11} \n" // restore R4-R11
"CPSIE I \n" // enable interrupts
"BX LR \n" // exit exception
".align 4 \n"
);
}
void __attribute__((naked))
StartOS(void) {
__asm volatile (
"LDR R0, =run_pt \n" // address of run_pt
"LDR R1, [R0] \n" // R1 = run_pt
"LDR SP, [R1] \n" // SP = run_pt->sp
"POP {R4-R11} \n" // restore R4-R11
"POP {R0-R3} \n" // restore R0-R3
"POP {R12} \n" // restore R12
"ADD SP, SP, #4 \n" // skip LR
"POP {LR} \n" // load thread start address
"ADD SP, SP, #4 \n" // skip PSR
"CPSIE I \n" // enable interrupts
"BX LR \n" // start thread
".align 4 \n"
);
}
void SetInitialStack(int i) {
tcbs[i].sp = &stacks[i][STACKSIZE-16];
stacks[i][STACKSIZE-1] = 0x01000000; // xPSR thumb bit
stacks[i][STACKSIZE-16] = 16; // R4
stacks[i][STACKSIZE-15] = 15; // R5
stacks[i][STACKSIZE-14] = 14; // R6
stacks[i][STACKSIZE-13] = 13; // R7
stacks[i][STACKSIZE-12] = 12; // R8
stacks[i][STACKSIZE-11] = 11; // R9
stacks[i][STACKSIZE-10] = 10; // R10
stacks[i][STACKSIZE-9] = 9; // R11
stacks[i][STACKSIZE-8] = 8; // R0
stacks[i][STACKSIZE-7] = 7; // R1
stacks[i][STACKSIZE-6] = 6; // R2
stacks[i][STACKSIZE-5] = 5; // R3
stacks[i][STACKSIZE-4] = 4; // R12
stacks[i][STACKSIZE-3] = 0; // LR (0 causes fault if thread returns)
}
// Initialize operating system, disable interrupts
// Initialize OS controlled I/O: systick, bus clock as fast as possible
void RoundRobinInit(void) {
CPU_cpsid();
ClockInit48MHz();
// Write TimerA1Init here 1000 Hz
}
void AddThreads(void (**threads)(void)) {
uint32_t i = 0;
for (; i < THREADS; ++i) {
SetInitialStack(i);
stacks[i][STACKSIZE-2] = (int32_t)threads[i];
tcbs[i].next = &tcbs[ (i+1) % THREADS ];
tcbs[i].blocked = 0;
tcbs[i].sleep = 0;
// tcbs[i].priority = p0;
}
run_pt = &tcbs[0];
}
void AddPeriodicEventThreads(PeriodicEvent_t *periodic_events) {
uint32_t i = 0;
for (;i < PERIODIC_THREADS; ++i) {
periodic_event_threads[i] = periodic_events[i];
}
}
void RoundRobinLaunch(uint32_t time_slice_cycles) {
SysTick->CTRL = 0; // 1) disable SysTick during setup
SysTick->LOAD = time_slice_cycles - 1; // 2) reload value sets period
SysTick->VAL = 0; // 3) any write to current clears it
SCB->SHP[11] = 7 << 5; // set priority into top 3 bits of 8-bit register
SysTick->CTRL = 0x00000007; // 4) enable SysTick with core clock and interrupts
TimerA1Init(RunPeriodicEvents, 5000); // 100Hz
StartOS(); // start on the first task
}
void RunPeriodicEvents(void) {
int32_t i;
for (i = 0; i < THREADS; ++i) {
if (tcbs[i].sleep) {
--(tcbs[i].sleep);
}
}
for (i = 0; i < PERIODIC_THREADS; ++i) {
periodic_event_threads[i].event();
}
}
void Scheduler(void) {
Tcb_t* t = run_pt->next;
while (t->blocked || t->sleep) {
t = t->next;
}
run_pt = t;
}
void Suspend(void) {
SysTick->VAL = 0; // clear
SCB->ICSR |= SCB_ICSR_PENDSTSET_Msk; // trigger
}
void Sleep(int32_t time) {
run_pt->sleep = time;
Suspend();
}
// Decrement semaphore
void Wait(int32_t *sema_pt) {
CPU_cpsid();
--(*sema_pt);
if((*sema_pt) < 0) {
run_pt->blocked = sema_pt; // reason it is blocked
CPU_cpsie();
Suspend();
}
CPU_cpsie();
}
// Increment semaphore
void Signal(int32_t *sema_pt) {
Tcb_t *pt;
CPU_cpsid();
++(*sema_pt);
if ((*sema_pt) <= 0) {
pt = run_pt->next;
while(pt->blocked != sema_pt) {
pt = pt->next;
}
pt->blocked = 0;
}
CPU_cpsie();
}

19
common/rtos.h Normal file
View File

@ -0,0 +1,19 @@
#ifndef RTOS_H
#define RTOS_H
#include <stdint.h>
typedef struct PeriodicEvent {
void (*event)(void);
uint32_t period_ms;
} PeriodicEvent_t;
void RoundRobinInit(void);
void AddThreads(void (**threads)(void));
void AddPeriodicEventThreads(PeriodicEvent_t *periodic_events);
void RoundRobinLaunch(uint32_t time_slice_cycles);
void Sleep(int32_t time);
void Wait(int32_t *sema_pt);
void Signal(int32_t *sema_pt);
#endif /* RTOS_H */

77
project/Makefile Normal file
View File

@ -0,0 +1,77 @@
CC = arm-none-eabi-gcc
# The location of the C compiler
# ARMGCC_ROOT is used by some makefiles that need to know where the compiler
# is installed.
ARMGCC_BIN := ${shell which ${CC}}
ifeq (${shell test -h ${ARMGCC_BIN} && echo "true" || echo "false"}, true)
ARMGCC_ROOT := ${shell dirname ${shell readlink ${ARMGCC_BIN}}}/..
else
ARMGCC_ROOT := ${shell dirname ${ARMGCC_BIN}}/..
endif
# Search for source files that are not in this directory
VPATH = ../common/
OBJECTS = main.o rtos.o timer_a1.o bump.o reflectance.o delay.o motor.o pwm.o cpu.o clock.o system.o startup.o syscalls.o
NAME = lab
CFLAGS = -I.. -I../inc -I../common \
-D__MSP432P401R__ \
-DDeviceFamily_MSP432P401x \
-mcpu=cortex-m4 \
-march=armv7e-m \
-mthumb \
-std=c99 \
-mfloat-abi=hard \
-mfpu=fpv4-sp-d16 \
-ffunction-sections \
-fdata-sections \
-gstrict-dwarf \
-Wall \
-I$(ARMGCC_ROOT)/arm-none-eabi/include/newlib-nano \
-I$(ARMGCC_ROOT)/arm-none-eabi/include
LFLAGS = -Wl,-T,../config.lds \
-Wl,-Map,$(NAME).map \
-march=armv7e-m \
-mthumb \
-mfloat-abi=hard \
-mfpu=fpv4-sp-d16 \
-static \
-Wl,--gc-sections \
-lgcc \
-lc \
-lm \
-lnosys \
--specs=nano.specs
all: $(NAME).out
@echo "SUCCESS: Compilation completed successfully."
%.o: %.c
@$(CC) $(CFLAGS) -g $< -c -o $@
cpu.o: ../common/cpu.c
@$(CC) $(CFLAGS) $< -c -o $@
clock.o: ../common/clock.c
@$(CC) $(CFLAGS) $< -c -o $@
system.o: ../system.c
@$(CC) $(CFLAGS) $< -c -o $@
startup.o: ../startup.c
@$(CC) $(CFLAGS) $< -c -o $@
syscalls.o: ../syscalls.c
@$(CC) $(CFLAGS) $< -c -o $@
$(NAME).out: $(OBJECTS)
@$(CC) $(OBJECTS) $(LFLAGS) -o $(NAME).out
clean: # Redirecting both the stderr and stdout to /dev/null
@rm -f $(OBJECTS) > /dev/null 2>&1
@rm -f $(NAME).out > /dev/null 2>&1
@rm -f $(NAME).map > /dev/null 2>&1

136
project/main.c Normal file
View File

@ -0,0 +1,136 @@
#include <stdint.h>
#include <stdbool.h>
#include <stdlib.h>
#include "../common/rtos.h"
#include "../common/pwm.h"
#include "../common/bump.h"
#include "../common/reflectance.h"
#include "../common/motor.h"
#include "../common/delay.h"
#include "inc/msp432p401r.h"
// bit-banded addresses, positive logic
#define SW2IN ((*((volatile uint8_t *)(0x42098010)))^1)
#define SW1IN ((*((volatile uint8_t *)(0x42098004)))^1)
// bit-banded address
#define REDLED (*((volatile uint8_t *)(0x42098040)))
// bit-banded addresses
#define BLUEOUT (*((volatile uint8_t *)(0x42098068)))
#define GREENOUT (*((volatile uint8_t *)(0x42098064)))
#define REDOUT (*((volatile uint8_t *)(0x42098060)))
#define START_REFLECTANCE 9
int32_t bump_pressed; // semaphore
uint8_t bump_data, reflectance_data;
void WaitTouchRelease(void) {
while(!(SW1IN || SW2IN)); // wait for touch
while( SW1IN || SW2IN ); // wait for release
}
void SwitchInit(void) {
P1->SEL0 &= ~0x12;
P1->SEL1 &= ~0x12; // 1) configure P1.4 and P1.1 as GPIO
P1->DIR &= ~0x12; // 2) make P1.4 and P1.1 in
P1->REN |= 0x12; // 3) enable pull resistors on P1.4 and P1.1
P1->OUT |= 0x12; // P1.4 and P1.1 are pull-up
}
void RedLEDInit(void) {
P1->SEL0 &= ~0x01;
P1->SEL1 &= ~0x01; // 1) configure P1.0 as GPIO
P1->DIR |= 0x01; // 2) make P1.0 out
}
void ColorLEDInit(void) {
P2->SEL0 &= ~0x07;
P2->SEL1 &= ~0x07; // 1) configure P2.2-P2.0 as GPIO
P2->DIR |= 0x07; // 2) make P2.2-P2.0 out
P2->DS |= 0x07; // 3) activate increased drive strength
P2->OUT &= ~0x07; // all LEDs off
}
void led_task(void) {
while (true) {
if (SW1IN && SW2IN) {
GREENOUT = 1;
} else {
GREENOUT = 0;
}
if (SW1IN || SW2IN) {
REDLED = 1;
} else {
REDLED = 0;
}
if (SW1IN) {
BLUEOUT = 1;
} else {
BLUEOUT = 0;
}
if (SW2IN) {
REDOUT = 1;
} else {
REDOUT = 0;
}
}
}
void drive_task(void) {
while (1) {
bump_pressed = 0;
MotorForward(1000, 1000);
Wait(&bump_pressed);
MotorBackward(800, 800);
Sleep(1000);
MotorLeft(800, 800);
Sleep(2000);
}
}
uint32_t refl_tick_count = 0;
void reflectance_task(void) {
++refl_tick_count;
if (1 == (refl_tick_count % 10)) {
ReflectanceStart();
}
if (2 == (refl_tick_count % 10)) {
reflectance_data = ReflectanceEnd();
}
}
void bump_task(void) {
bump_data = BumpRead();
if ((~bump_data & BUMP_PINS)) {
Signal(&bump_pressed);
}
}
int main(void) {
BumpInit();
ReflectanceInit();
PWMInitMotor(3751);
MotorInit();
RedLEDInit();
ColorLEDInit();
SwitchInit();
RoundRobinInit();
AddThreads((void (*[])(void)){
led_task,
drive_task
});
AddPeriodicEventThreads((PeriodicEvent_t []) {
{reflectance_task, 1},
{bump_task, 100}
});
RoundRobinLaunch(48000); // 1ms
return 0; // never executes
}