diff --git a/doc/SPI_Assignment/LA-Part3_Erase_Success.png b/doc/SPI_Assignment/LA-Part3_Erase_Success.png new file mode 100644 index 0000000..7f550dd Binary files /dev/null and b/doc/SPI_Assignment/LA-Part3_Erase_Success.png differ diff --git a/doc/SPI_Assignment/LA_PART1_Man_id.png b/doc/SPI_Assignment/LA_PART1_Man_id.png new file mode 100644 index 0000000..eff224c Binary files /dev/null and b/doc/SPI_Assignment/LA_PART1_Man_id.png differ diff --git a/doc/SPI_Assignment/LA_PART2_Mutex_help_2_Tasks.png b/doc/SPI_Assignment/LA_PART2_Mutex_help_2_Tasks.png new file mode 100644 index 0000000..9967c5e Binary files /dev/null and b/doc/SPI_Assignment/LA_PART2_Mutex_help_2_Tasks.png differ diff --git a/doc/SPI_Assignment/LA_Part3_Erase_start.png b/doc/SPI_Assignment/LA_Part3_Erase_start.png new file mode 100644 index 0000000..21a5267 Binary files /dev/null and b/doc/SPI_Assignment/LA_Part3_Erase_start.png differ diff --git a/doc/SPI_Assignment/LA_Part3_Read_Page_data.png b/doc/SPI_Assignment/LA_Part3_Read_Page_data.png new file mode 100644 index 0000000..d4ab8ce Binary files /dev/null and b/doc/SPI_Assignment/LA_Part3_Read_Page_data.png differ diff --git a/doc/SPI_Assignment/LA_Part3_Write_Page_data.png b/doc/SPI_Assignment/LA_Part3_Write_Page_data.png new file mode 100644 index 0000000..35c41f3 Binary files /dev/null and b/doc/SPI_Assignment/LA_Part3_Write_Page_data.png differ diff --git a/doc/SPI_Assignment/Readme.pdf b/doc/SPI_Assignment/Readme.pdf new file mode 100644 index 0000000..65175d0 Binary files /dev/null and b/doc/SPI_Assignment/Readme.pdf differ diff --git a/doc/SPI_Assignment/Telemetry_Part1.png b/doc/SPI_Assignment/Telemetry_Part1.png new file mode 100644 index 0000000..8029d70 Binary files /dev/null and b/doc/SPI_Assignment/Telemetry_Part1.png differ diff --git a/doc/SPI_Assignment/Telemetry_Part2.png b/doc/SPI_Assignment/Telemetry_Part2.png new file mode 100644 index 0000000..8620d13 Binary files /dev/null and b/doc/SPI_Assignment/Telemetry_Part2.png differ diff --git a/doc/SPI_Assignment/Telemetry_Part3_read_write_pages.png b/doc/SPI_Assignment/Telemetry_Part3_read_write_pages.png new file mode 100644 index 0000000..be19a00 Binary files /dev/null and b/doc/SPI_Assignment/Telemetry_Part3_read_write_pages.png differ diff --git a/projects/lpc40xx_freertos/assignment_include.h b/projects/lpc40xx_freertos/assignment_include.h new file mode 100644 index 0000000..10bbccb --- /dev/null +++ b/projects/lpc40xx_freertos/assignment_include.h @@ -0,0 +1,25 @@ +/** + * @file assignment_include.h + * @author Tejas Pidkalwar + * @date 19th Sept 2020 + * @brief This file maintains the macro defined to enable specific assignment implementation for + * execution, along with subparts of assignment enabling feature + */ +#ifndef _ASSIGNMENT_INCLUDE_ +#define _ASSIGNMENT_INCLUDE_ + +/* + * This file defines macros corresponding each assignment. + * Enable only one assignment macro while compiling. + * This file also defines macros for sub parts corresponding to each assignment. + * Take care to enable only one part macro enabled while compiling. + */ + +// Assignment 5 SPI +#define SPI_ASSIGNMENT +//#define PART0_SPI_ASSGNMT +//#define PART1_SPI_ASSGNMT +//#define PART2_SPI_ASSGNMT +#define PART3_SPI_ASSGNMT + +#endif \ No newline at end of file diff --git a/projects/lpc40xx_freertos/l3_drivers/sources/ssp2_lab.c b/projects/lpc40xx_freertos/l3_drivers/sources/ssp2_lab.c new file mode 100644 index 0000000..f86e888 --- /dev/null +++ b/projects/lpc40xx_freertos/l3_drivers/sources/ssp2_lab.c @@ -0,0 +1,60 @@ +/** + * @file ssp2_lab.c + * @author Tejas Pidkalwar + * @date 1st Oct 2020 + * @brief This file contains SSP2 driver configuration APIs + */ + +#include "clock.h" +#include "delay.h" +#include "gpio.h" +#include "lpc40xx.h" +#include "lpc_peripherals.h" +#include +#include + +void ssp2_lab_init(uint32_t max_clock_mhz) { + // Power on SSP2 peripheral + lpc_peripheral__turn_on_power_to(LPC_PERIPHERAL__SSP2); + + const uint32_t cpu_clock_mhz = clock__get_core_clock_hz() / (1000 * 1000); + // Clock diviser for SSP2 as 4 + LPC_SSP2->CPSR &= ~(0xFF); + LPC_SSP2->CPSR |= (cpu_clock_mhz / max_clock_mhz); + + // Configure CR0 register + LPC_SSP2->CR0 |= (0b111 << 0); + + // Configure CR1 register + LPC_SSP2->CR1 |= (1 << 1); +} + +void ssp2_configure_pin_functions(void) { + // Select SSP pin clock + gpio__construct_with_function(GPIO__PORT_1, 0, GPIO__FUNCTION_4); + + // Select SSP pin MOSI + gpio__construct_with_function(GPIO__PORT_1, 1, GPIO__FUNCTION_4); + + // Select SSP pin MISO + gpio__construct_with_function(GPIO__PORT_1, 4, GPIO__FUNCTION_4); + + // Select CS + gpio_s gpio_ssp_select = gpio__construct_as_output(GPIO__PORT_1, 10); + // Active low single needs be set by default + gpio__set(gpio_ssp_select); + + // Select CS pin to replicate original CS operation to monitor on Logic Analyzer + gpio_s gpio_ssp_select_replicate = gpio__construct_as_output(GPIO__PORT_0, 6); + // Active low single needs be set by default + gpio__set(gpio_ssp_select_replicate); +} + +uint8_t ssp2_lab_exchange_byte(uint8_t data_out) { + // Update Data Register with the given Data + LPC_SSP2->DR = data_out; + while ((LPC_SSP2->SR & (1 << 4))) { + ; + } + return LPC_SSP2->DR; +} diff --git a/projects/lpc40xx_freertos/l3_drivers/ssp2_lab.h b/projects/lpc40xx_freertos/l3_drivers/ssp2_lab.h new file mode 100644 index 0000000..7d78b4a --- /dev/null +++ b/projects/lpc40xx_freertos/l3_drivers/ssp2_lab.h @@ -0,0 +1,17 @@ +/** + * @file ssp2_lab.h + * @author Tejas Pidkalwar + * @date 1st Oct 2020 + * @brief This file contains SSP2 driver configuration APIs + */ + +#ifndef _SSP2_LAB_ +#define _SSP2_LAB_ + +void ssp2_lab_init(uint32_t max_clock_mhz); + +uint8_t ssp2_lab_exchange_byte(uint8_t data_out); + +void ssp2_configure_pin_functions(void); + +#endif \ No newline at end of file diff --git a/projects/lpc40xx_freertos/l4_io/adesto_flash/adesto_flash.c b/projects/lpc40xx_freertos/l4_io/adesto_flash/adesto_flash.c new file mode 100644 index 0000000..d5defa6 --- /dev/null +++ b/projects/lpc40xx_freertos/l4_io/adesto_flash/adesto_flash.c @@ -0,0 +1,128 @@ +/** + * @file adesto_flash.c + * @author Tejas Pidkalwar + * @date 1st Oct 2020 + * @brief This file contains the Adesto flash configuration APIs + */ + +#include "adesto_flash.h" +#include "ssp2_lab.h" +#include "stdio.h" + +const uint8_t dummy_byte = 0xFF; + +// TODO: Implement Adesto flash memory CS signal as a GPIO driver +void adesto_cs(void) { + LPC_GPIO1->CLR = (1 << 10); + LPC_GPIO0->CLR = (1 << 6); +} +void adesto_ds(void) { + LPC_GPIO1->SET = (1 << 10); + LPC_GPIO0->SET = (1 << 6); +} + +#if defined(PART1_SPI_ASSGNMT) || defined(PART2_SPI_ASSGNMT) + +// TODO: Implement the code to read Adesto flash memory signature +// TODO: Create struct of type 'adesto_flash_id_s' and return it +adesto_flash_id_s adesto_read_signature(void) { + adesto_flash_id_s data = {0}; + const uint8_t flash_id_read_opcode = 0x9F; + adesto_cs(); + { + // Send the opcode to trigger manufacturing ID read from flash + ssp2_lab_exchange_byte(flash_id_read_opcode); + // read out the manufacturing id from Flash by sending dummy bytes + data.manufacturer_id = ssp2_lab_exchange_byte(dummy_byte); + data.device_id_1 = ssp2_lab_exchange_byte(dummy_byte); + data.device_id_2 = ssp2_lab_exchange_byte(dummy_byte); + data.extended_device_id = ssp2_lab_exchange_byte(dummy_byte); + } + adesto_ds(); + + return data; +} + +#endif + +#ifdef PART3_SPI_ASSGNMT + +/** + * Send the 3 Bytes of address from the given one + * @param address Address bytes to be sent + */ +static void adesto_flash_send_address(uint32_t address) { + (void)ssp2_lab_exchange_byte((address >> 16) & 0xFF); + (void)ssp2_lab_exchange_byte((address >> 8) & 0xFF); + (void)ssp2_lab_exchange_byte((address >> 0) & 0xFF); +} + +/** + * Set the write enable latch WEL bit of status register byte 1 + */ +static void adesto_flash_WEL_bit_set(void) { + const uint8_t wel_bit_set_opcode = 0x06; + adesto_cs(); + ssp2_lab_exchange_byte(wel_bit_set_opcode); + adesto_ds(); +} + +/** + * Erase the 4K block of memory starting from given address + * @param erase_address Block's starting address to be erased + */ +static void adesto_flash_erase_4k_block(const uint32_t erase_address) { + uint8_t status_reg_read_opcode = 0x05; + uint8_t status_byte1 = 0x5; + uint8_t erase_4k_block_opcode = 0x20; + // Start of Erase Sequence + adesto_flash_WEL_bit_set(); + adesto_cs(); + ssp2_lab_exchange_byte(erase_4k_block_opcode); + adesto_flash_send_address(erase_address); + adesto_ds(); + + // Wait for erase operation to complete by polling on flash status register's Busy bit + adesto_cs(); + ssp2_lab_exchange_byte(status_reg_read_opcode); + do { + status_byte1 = ssp2_lab_exchange_byte(dummy_byte); + } while (status_byte1 & (1 << 0)); + adesto_ds(); + fprintf(stderr, "Current status register value byte1 is %x and hence ", status_byte1); + fprintf(stderr, "Erased successfully\n =>"); +} + +void adesto_flash_page_write(void) { + const uint8_t page_write_opcode = 0x02; + const uint32_t address_to_write = 0x000000; + const uint8_t data = 0xDA; + // Erase the memory to be written + adesto_flash_erase_4k_block(address_to_write); + + // Set WEL bit of Status register + adesto_flash_WEL_bit_set(); + + // Start the flash write sequence + adesto_cs(); + ssp2_lab_exchange_byte(page_write_opcode); + adesto_flash_send_address(address_to_write); + ssp2_lab_exchange_byte(data); + adesto_ds(); + fprintf(stderr, " writen data '%X' successfully\n =>", data); +} + +void adesto_flash_page_read(void) { + uint8_t read_data = 0x00; + const uint32_t address_to_write = 0x000000; + const uint8_t page_read_opcode = 0x0B; + adesto_cs(); + ssp2_lab_exchange_byte(page_read_opcode); + adesto_flash_send_address(address_to_write); + ssp2_lab_exchange_byte(dummy_byte); + read_data = ssp2_lab_exchange_byte(dummy_byte); + adesto_ds(); + fprintf(stderr, "Now, read data '%X' successfully\n", read_data); +} + +#endif diff --git a/projects/lpc40xx_freertos/l4_io/adesto_flash/adesto_flash.h b/projects/lpc40xx_freertos/l4_io/adesto_flash/adesto_flash.h new file mode 100644 index 0000000..86fb97f --- /dev/null +++ b/projects/lpc40xx_freertos/l4_io/adesto_flash/adesto_flash.h @@ -0,0 +1,49 @@ +/** + * @file adesto_flash.h + * @author Tejas Pidkalwar + * @date 1st Oct 2020 + * @brief This file contains the Adesto flash configuration APIs + */ +#ifndef _ADESTO_FLASH_ +#define _ADESTO_FLASH_ + +#include "gpio.h" +#include "lpc40xx.h" + +/** + * the Adesto flash 'Manufacturer and Device ID' section + */ +typedef struct { + uint8_t manufacturer_id; + uint8_t device_id_1; + uint8_t device_id_2; + uint8_t extended_device_id; +} adesto_flash_id_s; + +/** + * Assert the Slave select pin for SSP2 driver + */ +void adesto_cs(void); + +/** + * De-assert the Slave select pin for SSP2 driver + */ +void adesto_ds(void); + +/** + * Read the Flash manufacturing and device id information + * @return flash id structure with read information + */ +adesto_flash_id_s adesto_read_signature(void); + +/** + * Reads the page of a flash at given address + */ +void adesto_flash_page_read(void); + +/** + * Writes the page of a flash at given address + */ +void adesto_flash_page_write(void); + +#endif \ No newline at end of file diff --git a/projects/lpc40xx_freertos/l5_application/main.c b/projects/lpc40xx_freertos/l5_application/main.c index 3194d1d..552b930 100644 --- a/projects/lpc40xx_freertos/l5_application/main.c +++ b/projects/lpc40xx_freertos/l5_application/main.c @@ -9,21 +9,131 @@ #include "periodic_scheduler.h" #include "sj2_cli.h" +#ifdef SPI_ASSIGNMENT + +#include "adesto_flash.h" +#include "semphr.h" +#include "ssp2_lab.h" + +#ifdef PART1_SPI_ASSGNMT +void spi_task(void *p); +#endif + +#ifdef PART2_SPI_ASSGNMT +void spi_id_verification_task(void *p); +SemaphoreHandle_t spi_bus_mutex; +#endif + +#ifdef PART3_SPI_ASSGNMT +SemaphoreHandle_t write_read_page_mutex; + +void flash_page_read_task(void *p); +void flash_page_write_task(void *p); +#endif + +#else + static void create_blinky_tasks(void); static void create_uart_task(void); static void blink_task(void *params); static void uart_task(void *params); +#endif + int main(void) { +#ifdef SPI_ASSIGNMENT + // Initialize the SPI clock with given frequency + const uint32_t spi_clock_mhz = 6; + ssp2_lab_init(spi_clock_mhz); + + // Configure the SPI pins + ssp2_configure_pin_functions(); + +#ifdef PART1_SPI_ASSGNMT + xTaskCreate(spi_task, "spi", 2048 / sizeof(void *), NULL, PRIORITY_LOW, NULL); +#endif + +#ifdef PART2_SPI_ASSGNMT + spi_bus_mutex = xSemaphoreCreateMutex(); + + xTaskCreate(spi_id_verification_task, "id_verify", 2048 / sizeof(void *), NULL, PRIORITY_LOW, NULL); + xTaskCreate(spi_id_verification_task, "id_verify1", 2048 / sizeof(void *), NULL, PRIORITY_LOW, NULL); +#endif + +#ifdef PART3_SPI_ASSGNMT + + write_read_page_mutex = xSemaphoreCreateMutex(); + xTaskCreate(flash_page_write_task, "page_write", 2048 / sizeof(void *), NULL, PRIORITY_MEDIUM, NULL); + xTaskCreate(flash_page_read_task, "page_read", 2048 / sizeof(void *), NULL, PRIORITY_LOW, NULL); +#endif +#else create_blinky_tasks(); create_uart_task(); - +#endif puts("Starting RTOS"); vTaskStartScheduler(); // This function never returns unless RTOS scheduler runs out of memory and fails return 0; } +#ifdef SPI_ASSIGNMENT + +#ifdef PART1_SPI_ASSGNMT + +void spi_task(void *p) { + while (1) { + adesto_flash_id_s id = adesto_read_signature(); + fprintf(stderr, " Manufacturing id is: %X, %X, %X, %X\n", id.manufacturer_id, id.device_id_1, id.device_id_2, + id.extended_device_id); + + vTaskDelay(2000); + } +} +#endif + +#ifdef PART2_SPI_ASSGNMT +void spi_id_verification_task(void *p) { + while (1) { + adesto_flash_id_s id = {0}; + if (xSemaphoreTake(spi_bus_mutex, 1000)) { + id = adesto_read_signature(); + if (id.manufacturer_id != 0x1f) { + // When we read a manufacturer ID we do not expect, we will kill this task if (id.manufacturer_id != 0x1F) { + fprintf(stderr, "Manufacturer ID read failure\n"); + vTaskSuspend(NULL); // Kill this task + } + fprintf(stderr, "Task read manufacturing id as %x\n", id.manufacturer_id); + xSemaphoreGive(spi_bus_mutex); + } + } +} +#endif + +#ifdef PART3_SPI_ASSGNMT +void flash_page_read_task(void *p) { + while (1) { + if (xSemaphoreTake(write_read_page_mutex, 1000)) { + adesto_flash_page_read(); + xSemaphoreGive(write_read_page_mutex); + } + vTaskDelay(500); + } +} + +void flash_page_write_task(void *p) { + while (1) { + if (xSemaphoreTake(write_read_page_mutex, 1000)) { + adesto_flash_page_write(); + xSemaphoreGive(write_read_page_mutex); + } + vTaskDelay(500); + } +} + +#endif + +#else + static void create_blinky_tasks(void) { /** * Use '#if (1)' if you wish to observe how two tasks can blink LEDs @@ -98,3 +208,4 @@ static void uart_task(void *params) { printf(" %lu ticks\n\n", (xTaskGetTickCount() - ticks)); } } +#endif diff --git a/projects/lpc40xx_freertos/lpc40xx.h b/projects/lpc40xx_freertos/lpc40xx.h index 2f138cb..a6b9e54 100644 --- a/projects/lpc40xx_freertos/lpc40xx.h +++ b/projects/lpc40xx_freertos/lpc40xx.h @@ -27,6 +27,8 @@ #ifndef __LPC407x_8x_H__ #define __LPC407x_8x_H__ +#include "assignment_include.h" + /* * ========================================================================== * ---------- Interrupt Number Definition -----------------------------------