GCC Code Coverage Report


Directory: ../../
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 56.1% 120 / 0 / 214
Functions: 73.3% 11 / 0 / 15
Branches: 26.2% 21 / 0 / 80

driver/flash/flash.c
Line Branch Exec Source
1 /*******************************************************************************
2 *
3 * FILE:
4 * flash.c
5 *
6 * DESCRIPTION:
7 * Contains API functions for writing and reading data from the engine
8 * controller's flash.
9 *
10 * NOTE:
11 * This is the "legacy" flash driver for the 4MBit
12 * SST25VF040B-50-4I-S2AE-T flash chip used on old liquids & flight
13 * boards.
14 *
15 * COPYRIGHT:
16 * Copyright (c) 2025 Sun Devil Rocketry.
17 * All rights reserved.
18 *
19 * This software is licensed under terms that can be found in the LICENSE
20 * file in the root directory of this software component.
21 * If no LICENSE file comes with this software, it is covered under the
22 * BSD-3-Clause.
23 *
24 * https://opensource.org/license/bsd-3-clause
25 *
26 *******************************************************************************/
27
28
29 /*------------------------------------------------------------------------------
30 Standard Includes
31 ------------------------------------------------------------------------------*/
32 #include <string.h>
33
34
35 /*------------------------------------------------------------------------------
36 MCU Pins
37 ------------------------------------------------------------------------------*/
38 #if defined( FLIGHT_COMPUTER )
39 #include "sdr_pin_defines_A0002.h"
40 #elif defined( ENGINE_CONTROLLER )
41 #include "sdr_pin_defines_L0002.h"
42 #elif defined( FLIGHT_COMPUTER_LITE )
43 #include "sdr_pin_defines_A0007.h"
44 #endif
45
46
47 /*------------------------------------------------------------------------------
48 Project Includes
49 ------------------------------------------------------------------------------*/
50 #include "main.h"
51 #include "flash.h"
52 #include "usb.h"
53 #include "led.h"
54
55 #ifdef EMULATOR
56 #include "emulator.h"
57 #endif
58
59 /*------------------------------------------------------------------------------
60 Global Variables
61 ------------------------------------------------------------------------------*/
62 static bool write_enabled = false;
63
64
65 /*------------------------------------------------------------------------------
66 Internal function prototypes
67 ------------------------------------------------------------------------------*/
68
69 /* Converts a flash memory address in uint32_t format to a byte array */
70 static void address_to_bytes
71 (
72 uint32_t address,
73 uint8_t* address_bytes
74 );
75
76 /* Converts a flash memory address in byte format to uint32_t format */
77 static inline uint32_t bytes_to_address
78 (
79 uint8_t address_bytes[3]
80 );
81
82 /* Enable writing to the external flash chip hardware */
83 static FLASH_STATUS write_enable
84 (
85 void
86 );
87
88 /* Disable writing to the external flash chip hardware */
89 static FLASH_STATUS write_disable
90 (
91 void
92 );
93
94
95 /*------------------------------------------------------------------------------
96 Procedures
97 ------------------------------------------------------------------------------*/
98
99
100 /*******************************************************************************
101 * *
102 * PROCEDURE: *
103 * flash_cmd_execute *
104 * *
105 * DESCRIPTION: *
106 * Executes a flash subcommand based on input from the sdec terminal *
107 * *
108 *******************************************************************************/
109 ✗ FLASH_STATUS flash_cmd_execute
110 (
111 uint8_t subcommand ,
112 HFLASH_BUFFER* pflash_handle
113 )
114 {
115 /*------------------------------------------------------------------------------
116 Local Variables
117 ------------------------------------------------------------------------------*/
118 ✗ uint8_t opcode; /* Subcommand opcode */
119 ✗ uint8_t num_bytes; /* Number of bytes on which to
120 operate */
121 ✗ uint8_t address[3]; /* flash address in byte form */
122 ✗ uint8_t* pbuffer; /* Position within flash buffer */
123 ✗ uint8_t buffer[512]; /* buffer (flash extract) */
124 ✗ FLASH_STATUS flash_status; /* Return value of flash API calls */
125 ✗ USB_STATUS usb_status; /* Return value of USB API calls */
126
127
128 /*------------------------------------------------------------------------------
129 Pre-processing
130 ------------------------------------------------------------------------------*/
131 ✗ opcode = ( subcommand & FLASH_SUBCMD_OP_BITMASK ) >> 5;
132 ✗ num_bytes = ( subcommand & FLASH_NBYTES_BITMASK );
133 ✗ pflash_handle -> num_bytes = num_bytes;
134 ✗ pbuffer = &buffer[0];
135 ✗ memset( pbuffer, 0, sizeof( buffer ) );
136 ✗ address_to_bytes( pflash_handle -> address, &address[0] );
137
138
139 /*------------------------------------------------------------------------------
140 Call API function
141 ------------------------------------------------------------------------------*/
142 ✗ switch ( opcode )
143 {
144 /*-----------------------------READ Subcommand----------------------------*/
145 ✗ case FLASH_SUBCMD_READ:
146 {
147
148 /* Get flash address from USB */
149 ✗ usb_status = usb_receive( &( address[0] ) ,
150 sizeof( address ),
151 HAL_DEFAULT_TIMEOUT );
152
153 ✗ if ( usb_status != USB_OK )
154 {
155 return FLASH_USB_ERROR;
156 }
157 else
158 {
159 /* Call API Function */
160 ✗ pflash_handle -> address = bytes_to_address( address );
161 ✗ flash_status = flash_read( pflash_handle, num_bytes );
162
163 /* Check for flash error */
164 ✗ if ( flash_status != FLASH_OK )
165 {
166 /* Bytes not read */
167 return FLASH_FAIL;
168 }
169
170 /* Transmit bytes from pbuffer over USB */
171 ✗ usb_status = usb_transmit( pflash_handle -> pbuffer,
172 num_bytes ,
173 HAL_FLASH_TIMEOUT );
174
175 ✗ if ( usb_status != USB_OK )
176 {
177 /* Bytes not transimitted */
178 ✗ return FLASH_USB_ERROR;
179 }
180
181 }
182
183 /* Bytes read and transimitted back sucessfully */
184 return FLASH_OK;
185
186 } /* FLASH_SUBCMD_READ */
187
188 /*------------------------------ENABLE Subcommand-----------------------------*/
189 ✗ case FLASH_SUBCMD_ENABLE:
190 {
191 ✗ flash_write_enable();
192 ✗ return FLASH_OK;
193 } /* FLASH_SUBCMD_ENABLE */
194
195 /*------------------------------DISABLE Subcommand----------------------------*/
196 ✗ case FLASH_SUBCMD_DISABLE:
197 {
198 ✗ flash_write_disable();
199 ✗ return FLASH_OK;
200 } /* FLASH_SUBCMD_DISABLE */
201
202 /*------------------------------WRITE Subcommand------------------------------*/
203 ✗ case FLASH_SUBCMD_WRITE:
204 {
205 /* Get Address bits */
206 ✗ usb_status = usb_receive( &( address[0] ) ,
207 sizeof( address ),
208 HAL_DEFAULT_TIMEOUT );
209
210 ✗ if ( usb_status != USB_OK )
211 {
212 /* Address not recieved */
213 return FLASH_USB_ERROR;
214 }
215 else
216 {
217 /* Convert flash address to uint32_t */
218 ✗ pflash_handle -> address = bytes_to_address( address );
219
220 /* Get bytes to be written to flash */
221 ✗ for ( int i = 0; i < num_bytes; i++ )
222 {
223 ✗ pbuffer = ( pflash_handle -> pbuffer ) + i;
224 ✗ flash_status = usb_receive( pbuffer ,
225 sizeof( uint8_t ),
226 HAL_DEFAULT_TIMEOUT );
227
228 /* Return if usb call failed */
229 ✗ if ( usb_status != USB_OK )
230 {
231 /* Bytes not received */
232 return FLASH_USB_ERROR;
233 }
234
235 }
236 }
237
238 /* Call API function */
239 ✗ flash_status = flash_write( pflash_handle );
240
241 ✗ return flash_status;
242 } /* FLASH_SUBCMD_WRITE */
243
244 /*------------------------------ERASE Subcommand------------------------------*/
245 ✗ case FLASH_SUBCMD_ERASE:
246 {
247 /* Call API Function*/
248 ✗ flash_status = flash_erase( pflash_handle );
249
250 ✗ return flash_status;
251 } /* FLASH_SUBCMD_ERASE */
252
253 /*------------------------------STATUS Subcommand-----------------------------*/
254 ✗ case FLASH_SUBCMD_STATUS:
255 {
256 /* Call API function */
257 ✗ flash_status = flash_get_status( pflash_handle );
258
259 /* Send status register contents back to PC */
260 ✗ usb_status = usb_transmit( &( pflash_handle -> status_register ),
261 sizeof( uint8_t ) ,
262 HAL_DEFAULT_TIMEOUT );
263
264 /* Return status code */
265 ✗ if ( usb_status != USB_OK )
266 {
267 return FLASH_USB_ERROR;
268 }
269 ✗ else if ( flash_status != FLASH_OK )
270 {
271 return FLASH_SPI_ERROR;
272 }
273 else
274 {
275 ✗ return FLASH_OK;
276 }
277 } /* FLASH_SUBCMD_STATUS */
278
279 /*-----------------------------EXTRACT Subcommand-----------------------------*/
280 ✗ case FLASH_SUBCMD_EXTRACT:
281 {
282 /* Extracts the entire flash chip, flash chip address from 0 to 0x7FFFF */
283 ✗ pflash_handle->pbuffer = &buffer[0];
284 ✗ pflash_handle->address = 0;
285 ✗ while( pflash_handle->address <= FLASH_MAX_ADDR )
286 {
287 ✗ flash_status = flash_read( pflash_handle, sizeof( buffer ) );
288 ✗ if( flash_status == FLASH_OK )
289 {
290 ✗ usb_transmit( &buffer, sizeof( buffer ), HAL_FLASH_TIMEOUT );
291 }
292 else
293 {
294 /* Extract Failed */
295 return FLASH_EXTRACT_ERROR;
296 }
297
298 /* Read from next address */
299 ✗ (pflash_handle->address) += sizeof( buffer ) ;
300
301 #if defined( EMULATOR ) && defined( __linux__ )
302 ✗ HAL_Delay(15); /* add a small delay -- SDEC reads slower than we tx */
303 #endif
304 }
305
306 return FLASH_OK;
307 } /* FLASH_SUBCMD_EXTRACT */
308
309 /*---------------------------Unrecognized Subcommand--------------------------*/
310 default:
311 {
312 return FLASH_UNRECOGNIZED_OP;
313 }
314
315 }
316 } /* flash_cmd_execute */
317
318
319 /*******************************************************************************
320 * *
321 * PROCEDURE: *
322 * flash_init *
323 * *
324 * DESCRIPTION: *
325 * Initializes the flash chip *
326 * *
327 *******************************************************************************/
328 2 FLASH_STATUS flash_init
329 (
330 HFLASH_BUFFER* pflash_handle /* Flash handle */
331 )
332 {
333 /*------------------------------------------------------------------------------
334 Local variables
335 ------------------------------------------------------------------------------*/
336 2 FLASH_STATUS flash_status; /* Flash API function return codes */
337 2 uint8_t status_register; /* Desired status register contents */
338
339
340 /*------------------------------------------------------------------------------
341 Initializations
342 ------------------------------------------------------------------------------*/
343 2 flash_status = FLASH_OK;
344 2 status_register = FLASH_REG_RESET_VAL;
345
346
347 /*------------------------------------------------------------------------------
348 Pre-processing
349 ------------------------------------------------------------------------------*/
350
351 /* Check for invalid BPL setting */
352
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if ( pflash_handle -> bpl_bits > FLASH_BPL_ALL )
353 {
354 return FLASH_INVALID_INPUT;
355 }
356
357 /* Determine the desired status register contents */
358 2 status_register &= pflash_handle -> bpl_bits;
359 2 status_register |= pflash_handle -> bpl_write_protect;
360
361
362 /*------------------------------------------------------------------------------
363 API Function Implementation
364 ------------------------------------------------------------------------------*/
365
366 /* Configure write protection */
367
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if ( pflash_handle -> write_protected )
368 {
369 ✗ flash_write_disable();
370 ✗ return FLASH_OK;
371 }
372 else
373 {
374 2 flash_write_enable();
375 }
376
377 /* Check the flash chip status register to confirm chip can be reached */
378 2 flash_status = flash_get_status( pflash_handle );
379
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if ( flash_status != FLASH_OK )
380 {
381 return flash_status;
382 }
383
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 else if ( pflash_handle -> status_register == 0xFF )
384 {
385 return FLASH_INIT_FAIL;
386 }
387
388 /* Disable writing to the chip in case of prior interrupted write operation */
389
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 if ( write_disable() != FLASH_OK )
390 {
391 return FLASH_CANNOT_WRITE_DISABLE;
392 }
393
394 /* Set the bpl bits in the flash chip */
395 2 flash_status = flash_set_status( status_register );
396
397 /* Confirm Status register contents */
398
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
2 while( flash_is_flash_busy() == FLASH_BUSY ){}
399 2 flash_status = flash_get_status( pflash_handle );
400
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if ( pflash_handle -> status_register != status_register )
401 {
402 return FLASH_INIT_FAIL;
403 }
404 else
405 {
406 2 return flash_status;
407 }
408
409 } /* flash_init */
410
411
412 /*******************************************************************************
413 * *
414 * PROCEDURE: *
415 * flash_get_status *
416 * *
417 * DESCRIPTION: *
418 * Read the status register of the flash chip *
419 * *
420 *******************************************************************************/
421 10707 FLASH_STATUS flash_get_status
422 (
423 HFLASH_BUFFER* pflash_handle
424 )
425 {
426 /*------------------------------------------------------------------------------
427 Local variables
428 ------------------------------------------------------------------------------*/
429 10707 HAL_StatusTypeDef hal_status[2]; /* Status codes returned by SPI HAL */
430 10707 uint8_t flash_opcode; /* Data to be transmitted over SPI */
431
432 /*------------------------------------------------------------------------------
433 Initialiazations
434 ------------------------------------------------------------------------------*/
435 10707 flash_opcode = FLASH_OP_HW_RDSR;
436
437
438 /*------------------------------------------------------------------------------
439 API function implementation
440 ------------------------------------------------------------------------------*/
441
442 /* Drive slave select line low */
443 10707 HAL_GPIO_WritePin( FLASH_SS_GPIO_PORT,
444 FLASH_SS_PIN ,
445 GPIO_PIN_RESET );
446
447 /* Send RDSR code to flash chip */
448 10707 hal_status[0] = HAL_SPI_Transmit( &( FLASH_SPI ) ,
449 &flash_opcode ,
450 sizeof( flash_opcode ),
451 HAL_DEFAULT_TIMEOUT );
452
453 /* Recieve status code */
454 10706 hal_status[1] = HAL_SPI_Receive( &( FLASH_SPI ),
455 &( pflash_handle -> status_register ),
456 sizeof( pflash_handle -> status_register ),
457 HAL_DEFAULT_TIMEOUT );
458
459 /* Drive slave select line high */
460 10706 HAL_GPIO_WritePin( FLASH_SS_GPIO_PORT,
461 FLASH_SS_PIN ,
462 GPIO_PIN_SET );
463
464 /* Return flash status code */
465
2/4
✓ Branch 0 taken 10706 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 10706 times.
✗ Branch 3 not taken.
10706 if ( hal_status[0] != HAL_OK || hal_status[1] != HAL_OK )
466 {
467 return FLASH_SPI_ERROR;
468 }
469 else
470 {
471 10706 return FLASH_OK;
472 }
473
474 } /* flash_get_status */
475
476
477 /*******************************************************************************
478 * *
479 * PROCEDURE: *
480 * flash_set_status *
481 * *
482 * DESCRIPTION: *
483 * Writes to the status register *
484 * *
485 *******************************************************************************/
486 2 FLASH_STATUS flash_set_status
487 (
488 uint8_t flash_status
489 )
490 {
491 /*------------------------------------------------------------------------------
492 Local variables
493 ------------------------------------------------------------------------------*/
494 2 uint8_t hal_status [3]; /* Status code returned by hal spi functions */
495 2 uint8_t flash_opcodes[2]; /* Flash instruction cycle bytes */
496
497
498 /*------------------------------------------------------------------------------
499 Initializations
500 ------------------------------------------------------------------------------*/
501 2 flash_opcodes[0] = FLASH_OP_HW_EWSR;
502 2 flash_opcodes[1] = FLASH_OP_HW_WRSR;
503
504
505 /*------------------------------------------------------------------------------
506 Pre-processing
507 ------------------------------------------------------------------------------*/
508
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if ( !( write_enabled ) )
509 {
510 return FLASH_WRITE_PROTECTED;
511 }
512
513
514 /*------------------------------------------------------------------------------
515 API function implementation
516 ------------------------------------------------------------------------------*/
517
518 /* Enable write to status register */
519 2 HAL_GPIO_WritePin( FLASH_SS_GPIO_PORT,
520 FLASH_SS_PIN ,
521 GPIO_PIN_RESET );
522 2 hal_status[0] = HAL_SPI_Transmit( &( FLASH_SPI ) ,
523 &flash_opcodes[0],
524 sizeof( uint8_t ),
525 HAL_DEFAULT_TIMEOUT );
526 2 HAL_GPIO_WritePin( FLASH_SS_GPIO_PORT,
527 FLASH_SS_PIN ,
528 GPIO_PIN_SET );
529
530 /* Write the Data to the status register */
531 2 HAL_GPIO_WritePin( FLASH_SS_GPIO_PORT,
532 FLASH_SS_PIN ,
533 GPIO_PIN_RESET );
534 2 hal_status[1] = HAL_SPI_Transmit( &( FLASH_SPI ) ,
535 &flash_opcodes[1],
536 sizeof( uint8_t ),
537 HAL_DEFAULT_TIMEOUT );
538 2 hal_status[2] = HAL_SPI_Transmit( &( FLASH_SPI ) ,
539 &flash_status ,
540 sizeof( flash_status ),
541 HAL_DEFAULT_TIMEOUT );
542 2 HAL_GPIO_WritePin( FLASH_SS_GPIO_PORT,
543 FLASH_SS_PIN ,
544 GPIO_PIN_SET );
545
546 /* Return flash status */
547
2/4
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
2 if ( hal_status[0] != HAL_OK ||
548
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 hal_status[1] != HAL_OK ||
549 hal_status[2] != HAL_OK )
550 {
551 return FLASH_SPI_ERROR;
552 }
553 else
554 {
555 2 return FLASH_OK;
556 }
557
558 } /* flash_set_status */
559
560
561 /*******************************************************************************
562 * *
563 * PROCEDURE: *
564 * flash_is_flash_busy *
565 * *
566 * DESCRIPTION: *
567 * Polls the flash status register to see if the chip is busy. False *
568 * boolean return value indicates the chip is ready for write operations *
569 * *
570 *******************************************************************************/
571 10703 bool flash_is_flash_busy
572 (
573 void
574 )
575 {
576 /*------------------------------------------------------------------------------
577 Local variables
578 ------------------------------------------------------------------------------*/
579 10703 HFLASH_BUFFER flash_handle; /* Flash handle to store status reg contents */
580 10703 FLASH_STATUS flash_status; /* Flash API return codes */
581
582
583 /*------------------------------------------------------------------------------
584 Initializations
585 ------------------------------------------------------------------------------*/
586 10703 flash_status = FLASH_OK;
587 10703 flash_handle.status_register = 0xFF;
588
589
590 /*------------------------------------------------------------------------------
591 Implementation
592 ------------------------------------------------------------------------------*/
593
594 /* Read status register */
595 10703 flash_status = flash_get_status( &flash_handle );
596
1/2
✓ Branch 0 taken 10702 times.
✗ Branch 1 not taken.
10702 if ( flash_status != FLASH_OK )
597 {
598 return FLASH_BUSY;
599 }
600
1/2
✓ Branch 0 taken 10702 times.
✗ Branch 1 not taken.
10702 else if ( flash_handle.status_register & FLASH_BUSY_BITMASK )
601 {
602 return FLASH_BUSY;
603 }
604 else
605 {
606 10702 return FLASH_READY;
607 }
608
609 } /* flash_is_flash_busy */
610
611
612 /*******************************************************************************
613 * *
614 * PROCEDURE: *
615 * flash_write_enable *
616 * *
617 * DESCRIPTION: *
618 * Enable writing to the external flash chip by configuring the global *
619 * write protection variable *
620 * *
621 *******************************************************************************/
622 2 void flash_write_enable
623 (
624 void
625 )
626 {
627 2 write_enabled = true;
628 2 } /* flash_write_enable */
629
630
631 /*******************************************************************************
632 * *
633 * PROCEDURE: *
634 * flash_write_disable *
635 * *
636 * DESCRIPTION: *
637 * Disable writing to the external flash chip *
638 * *
639 *******************************************************************************/
640 ✗ void flash_write_disable
641 (
642 void
643 )
644 {
645 ✗ write_enabled = false;
646 ✗ } /* flash_write_disable */
647
648
649 /*******************************************************************************
650 * *
651 * PROCEDURE: *
652 * flash_write_byte *
653 * *
654 * DESCRIPTION: *
655 * writes a byte to the external flash *
656 * *
657 *******************************************************************************/
658 ✗ FLASH_STATUS flash_write_byte
659 (
660 HFLASH_BUFFER* pflash_handle,
661 uint8_t byte
662 )
663 {
664 /*------------------------------------------------------------------------------
665 Local variables
666 ------------------------------------------------------------------------------*/
667 ✗ HAL_StatusTypeDef hal_status[3]; /* Status code return by hal functions */
668 ✗ FLASH_STATUS flash_status; /* Status code returned by flash API */
669 ✗ uint8_t flash_opcode; /* Data to be transmitted over SPI */
670 ✗ uint8_t address[3]; /* Flash memory address in byte form */
671
672
673 /*------------------------------------------------------------------------------
674 Initializations
675 ------------------------------------------------------------------------------*/
676 ✗ flash_status = FLASH_OK;
677 ✗ flash_opcode = FLASH_OP_HW_BYTE_PROGRAM;
678 ✗ address_to_bytes( pflash_handle -> address, &address[0] );
679
680
681 /*------------------------------------------------------------------------------
682 Pre-processing
683 ------------------------------------------------------------------------------*/
684
685 /* Check if write_enabled */
686 ✗ if( !( write_enabled ) )
687 {
688 return FLASH_WRITE_PROTECTED;
689 }
690
691 /*------------------------------------------------------------------------------
692 API function implementation
693 ------------------------------------------------------------------------------*/
694
695 /* Enable the chip for writing */
696 ✗ flash_status = write_enable();
697 ✗ if ( flash_status != FLASH_OK )
698 {
699 return FLASH_CANNOT_WRITE_ENABLE;
700 }
701
702 /* Send the byte program command to the flash over SPI */
703 ✗ HAL_GPIO_WritePin( FLASH_SS_GPIO_PORT, FLASH_SS_PIN, GPIO_PIN_RESET );
704 ✗ hal_status[0] = HAL_SPI_Transmit( &( FLASH_SPI ) ,
705 &flash_opcode ,
706 sizeof( flash_opcode ),
707 HAL_DEFAULT_TIMEOUT );
708
709 /* Send address bytes */
710 ✗ hal_status[1] = HAL_SPI_Transmit( &( FLASH_SPI ) ,
711 &address[0] ,
712 sizeof( address ),
713 HAL_DEFAULT_TIMEOUT );
714
715 /* Write bytes */
716 ✗ hal_status[2] = HAL_SPI_Transmit( &( FLASH_SPI ),
717 &byte ,
718 sizeof( byte ) ,
719 HAL_FLASH_TIMEOUT );
720 ✗ HAL_GPIO_WritePin( FLASH_SS_GPIO_PORT, FLASH_SS_PIN, GPIO_PIN_SET );
721
722 /* Return flash status */
723 ✗ if ( hal_status[0] != HAL_OK ||
724 ✗ hal_status[1] != HAL_OK ||
725 hal_status[2] != HAL_OK )
726 {
727 return FLASH_SPI_ERROR;
728 }
729 else
730 {
731 ✗ return FLASH_OK;
732 }
733
734 } /* flash_write_byte */
735
736
737 /*******************************************************************************
738 * *
739 * PROCEDURE: *
740 * flash_write *
741 * *
742 * DESCRIPTION: *
743 * writes bytes from a flash buffer to the external flash *
744 * *
745 *******************************************************************************/
746 2 FLASH_STATUS flash_write
747 (
748 HFLASH_BUFFER* pflash_handle
749 )
750 {
751 /*------------------------------------------------------------------------------
752 Local variables
753 ------------------------------------------------------------------------------*/
754 2 HAL_StatusTypeDef hal_status[3]; /* Status codes returned by HAL */
755 2 FLASH_STATUS flash_status; /* Status codes returned by flash API */
756 2 uint8_t flash_opcode; /* Opcode for flash instructions */
757 2 uint32_t timeout; /* Timeout for flash write calls */
758 2 uint32_t timeout_ctr; /* Counter to trigger timeout */
759 2 uint8_t* pbuffer; /* Pointer to data in flash buffer */
760 2 uint8_t address_bytes[3]; /* Flash memory address in byte form */
761
762
763 /*------------------------------------------------------------------------------
764 Initializations
765 ------------------------------------------------------------------------------*/
766 2 flash_opcode = FLASH_OP_HW_AAI_PROGRAM;
767 2 flash_status = FLASH_OK;
768 2 timeout = pflash_handle -> num_bytes; /* 1 ms/byte timeout */
769 2 timeout_ctr = 0;
770 2 pbuffer = pflash_handle -> pbuffer;
771 2 address_to_bytes( pflash_handle -> address, &address_bytes[0] );
772
773
774 /*------------------------------------------------------------------------------
775 Pre-processing
776 ------------------------------------------------------------------------------*/
777
778 /* Check if write_enabled */
779
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if( !( write_enabled ) )
780 {
781 return FLASH_WRITE_PROTECTED;
782 }
783
784 /* Check for 1/0 byte edge case */
785
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if ( pflash_handle -> num_bytes == 1 )
786 {
787 ✗ return flash_write_byte( pflash_handle, *( pflash_handle -> pbuffer ) );
788 }
789
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 else if ( pflash_handle -> num_bytes == 0 )
790 {
791 return FLASH_ERROR_MISSING_DATA;
792 }
793
794
795 /*------------------------------------------------------------------------------
796 API function implementation
797 ------------------------------------------------------------------------------*/
798
799 /* Enable the chip for writing */
800 2 flash_status = write_enable();
801
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if ( flash_status != FLASH_OK )
802 {
803 return FLASH_CANNOT_WRITE_ENABLE;
804 }
805
806 /* Escape for emulator */
807 #ifdef EMULATOR
808 2 return emulator_flash_write( pflash_handle->pbuffer, pflash_handle->address, pflash_handle->num_bytes );
809 #endif
810
811 /* Initial SPI transmission */
812 HAL_GPIO_WritePin( FLASH_SS_GPIO_PORT, FLASH_SS_PIN, GPIO_PIN_RESET );
813 hal_status[0] = HAL_SPI_Transmit( &( FLASH_SPI ) ,
814 &flash_opcode ,
815 sizeof( flash_opcode ),
816 HAL_DEFAULT_TIMEOUT );
817 hal_status[1] = HAL_SPI_Transmit( &( FLASH_SPI ) ,
818 &address_bytes[0] ,
819 sizeof( address_bytes ),
820 HAL_DEFAULT_TIMEOUT );
821 hal_status[2] = HAL_SPI_Transmit( &( FLASH_SPI ),
822 pbuffer ,
823 2 ,
824 HAL_DEFAULT_TIMEOUT );
825 HAL_GPIO_WritePin( FLASH_SS_GPIO_PORT, FLASH_SS_PIN, GPIO_PIN_SET );
826
827 /* Check for SPI errors */
828 if ( hal_status[0] != HAL_OK ||
829 hal_status[1] != HAL_OK ||
830 hal_status[2] != HAL_OK )
831 {
832 return FLASH_SPI_ERROR;
833 }
834
835 /* Transmit remaining data */
836 for ( int i = 2; i < pflash_handle -> num_bytes; i += 2 )
837 {
838 /* Setup buffer pointer */
839 pbuffer += 2;
840
841 /* Wait for flash to be ready */
842 while( flash_is_flash_busy() == FLASH_BUSY )
843 {
844 if ( timeout_ctr >= timeout )
845 {
846 return FLASH_TIMEOUT;
847 }
848 else
849 {
850 timeout_ctr++;
851 }
852 }
853
854 /* SPI Transmission */
855 HAL_GPIO_WritePin( FLASH_SS_GPIO_PORT, FLASH_SS_PIN, GPIO_PIN_RESET );
856 hal_status[0] = HAL_SPI_Transmit( &( FLASH_SPI ) ,
857 &flash_opcode ,
858 sizeof( flash_opcode ),
859 HAL_DEFAULT_TIMEOUT );
860 hal_status[1] = HAL_SPI_Transmit( &( FLASH_SPI ),
861 pbuffer ,
862 2 ,
863 HAL_DEFAULT_TIMEOUT );
864 HAL_GPIO_WritePin( FLASH_SS_GPIO_PORT, FLASH_SS_PIN, GPIO_PIN_SET );
865
866 /* Check for errors */
867 if ( hal_status[0] != HAL_OK || hal_status[1] != HAL_OK )
868 {
869 return FLASH_WRITE_ERROR;
870 }
871
872 } /* for ( i < pflash_handle -> num_bytes )*/
873
874 /* Wait for AAI to complete */
875 while ( flash_is_flash_busy() == FLASH_BUSY ){}
876
877 /* Terminate AAI Programming */
878 flash_status = write_disable();
879 if ( flash_status != FLASH_OK )
880 {
881 return FLASH_CANNOT_EXIT_AAI;
882 }
883
884 /* Wait for WRDI to complete */
885 while ( flash_is_flash_busy() == FLASH_BUSY ){}
886
887 /* Transmit final byte if num_bytes is odd */
888 if ( ( pflash_handle -> num_bytes ) %2 == 1 )
889 {
890 pbuffer += 1;
891 return flash_write_byte( pflash_handle, *pbuffer );
892 }
893 else
894 {
895 /* Flash write successful */
896 return FLASH_OK;
897 }
898
899 } /* flash_write */
900
901
902 /*******************************************************************************
903 * *
904 * PROCEDURE: *
905 * flash_read *
906 * *
907 * DESCRIPTION: *
908 * reads a specified number of bytes using a flash buffer *
909 * *
910 *******************************************************************************/
911 10698 FLASH_STATUS flash_read
912 (
913 HFLASH_BUFFER* pflash_handle,
914 uint32_t num_bytes
915 )
916 {
917 /*------------------------------------------------------------------------------
918 Local variables
919 ------------------------------------------------------------------------------*/
920 10698 HAL_StatusTypeDef hal_status[4]; /* Status code return by hal spi functions */
921 10698 uint8_t flash_opcode; /* Data to be transmitted over SPI */
922 10698 uint8_t address[3]; /* Flash address in byte format */
923 10698 uint8_t* pbuffer; /* Pointer to position in output buffer */
924 10698 uint8_t dummy_byte; /* Dummy byte needed for high speed read */
925
926
927 /*------------------------------------------------------------------------------
928 Initializations
929 ------------------------------------------------------------------------------*/
930 10698 flash_opcode = FLASH_OP_HW_READ_HS;
931 10698 dummy_byte = 0;
932 10698 address_to_bytes( pflash_handle -> address, &address[0] );
933
934
935 /*------------------------------------------------------------------------------
936 API function implementation
937 ------------------------------------------------------------------------------*/
938
939 /* Escape for emulator */
940 #ifdef EMULATOR
941 10698 return emulator_flash_read( pflash_handle->pbuffer, pflash_handle->address, num_bytes );
942 #endif
943
944 /* Initiate SPI transmission */
945 HAL_GPIO_WritePin( FLASH_SS_GPIO_PORT, FLASH_SS_PIN, GPIO_PIN_RESET );
946
947 /* Command opcode */
948 hal_status[0] = HAL_SPI_Transmit( &( FLASH_SPI ) ,
949 &flash_opcode ,
950 sizeof( flash_opcode ),
951 HAL_DEFAULT_TIMEOUT );
952
953 /* Address */
954 hal_status[1] = HAL_SPI_Transmit( &( FLASH_SPI ) ,
955 &( address[0] ) ,
956 sizeof( address ),
957 HAL_DEFAULT_TIMEOUT );
958
959 /* Dummy Cycle */
960 hal_status[2] = HAL_SPI_Transmit( &( FLASH_SPI ) ,
961 &( dummy_byte ) ,
962 sizeof( dummy_byte ),
963 HAL_DEFAULT_TIMEOUT );
964
965 /* Check for SPI errors */
966 if ( hal_status[0] != HAL_OK ||
967 hal_status[1] != HAL_OK ||
968 hal_status[2] != HAL_OK )
969 {
970 return FLASH_SPI_ERROR;
971 }
972
973 /* Recieve output into buffer*/
974 for ( int i = 0; i < num_bytes; ++i )
975 {
976 pbuffer = ( pflash_handle -> pbuffer ) + i;
977 hal_status[3] = HAL_SPI_Receive( &( FLASH_SPI ) ,
978 pbuffer ,
979 sizeof( uint8_t ) ,
980 HAL_DEFAULT_TIMEOUT );
981
982 if ( hal_status[3] != HAL_OK )
983 {
984 return FLASH_SPI_ERROR;
985 }
986 }
987
988 /* Drive chip enable line high */
989 HAL_GPIO_WritePin( FLASH_SS_GPIO_PORT, FLASH_SS_PIN, GPIO_PIN_SET );
990
991 /* Flash read successful */
992 return FLASH_OK;
993
994 } /* flash_read */
995
996
997 /*******************************************************************************
998 * *
999 * PROCEDURE: *
1000 * flash_erase *
1001 * *
1002 * DESCRIPTION: *
1003 * erases the entire flash chip *
1004 * *
1005 *******************************************************************************/
1006 ✗ FLASH_STATUS flash_erase
1007 (
1008 HFLASH_BUFFER* pflash_handle
1009 )
1010 {
1011 /*------------------------------------------------------------------------------
1012 Local variables
1013 ------------------------------------------------------------------------------*/
1014 ✗ int8_t hal_status; /* Status code return by hal spi functions */
1015 ✗ uint8_t flash_opcode; /* Data to be transmitted over SPI */
1016 ✗ FLASH_STATUS flash_status;
1017
1018
1019 /*------------------------------------------------------------------------------
1020 Initializations
1021 ------------------------------------------------------------------------------*/
1022 ✗ flash_opcode = FLASH_OP_HW_FULL_ERASE;
1023
1024
1025 /*------------------------------------------------------------------------------
1026 Pre-processing
1027 ------------------------------------------------------------------------------*/
1028
1029 /* Check if write_enabled */
1030 ✗ if( !( write_enabled ) )
1031 {
1032 return FLASH_WRITE_PROTECTED;
1033 }
1034
1035
1036 /*------------------------------------------------------------------------------
1037 API function implementation
1038 ------------------------------------------------------------------------------*/
1039
1040 #ifdef EMULATOR
1041 ✗ return emulator_flash_erase();
1042 #endif
1043 /* Enable writing to flash */
1044 flash_status = write_enable();
1045
1046 /* Full chip erase */
1047 HAL_GPIO_WritePin( FLASH_SS_GPIO_PORT, FLASH_SS_PIN, GPIO_PIN_RESET );
1048 hal_status = HAL_SPI_Transmit( &( FLASH_SPI ) ,
1049 &flash_opcode ,
1050 sizeof( flash_opcode ),
1051 HAL_DEFAULT_TIMEOUT );
1052 HAL_GPIO_WritePin( FLASH_SS_GPIO_PORT, FLASH_SS_PIN, GPIO_PIN_SET );
1053
1054 /* Return status code */
1055 if ( hal_status != HAL_OK )
1056 {
1057 return FLASH_SPI_ERROR;
1058 }
1059 else if ( flash_status != FLASH_OK )
1060 {
1061 return FLASH_FAIL;
1062 }
1063 else
1064 {
1065 return FLASH_OK;
1066 }
1067
1068 } /* flash_erase */
1069
1070
1071 /*******************************************************************************
1072 * *
1073 * PROCEDURE: *
1074 * flash_block_erase *
1075 * *
1076 * DESCRIPTION: *
1077 * Erase a block of flash *
1078 * *
1079 *******************************************************************************/
1080 3 FLASH_STATUS flash_block_erase
1081 (
1082 FLASH_BLOCK flash_block_num, /* Block of flash to erase */
1083 FLASH_BLOCK_SIZE size /* Size of block */
1084 )
1085 {
1086 /*------------------------------------------------------------------------------
1087 Local variables
1088 ------------------------------------------------------------------------------*/
1089 3 int8_t hal_status[2]; /* Status code return by hal spi functions */
1090 3 uint8_t flash_opcode; /* Data to be transmitted over SPI */
1091 3 FLASH_STATUS flash_status; /* Return codes from flash API */
1092 3 uint32_t flash_addr; /* Address of block to erase */
1093 3 uint8_t flash_addr_bytes[3]; /* Address of block to erase in byte form */
1094
1095
1096 /*------------------------------------------------------------------------------
1097 Initializations
1098 ------------------------------------------------------------------------------*/
1099 3 flash_status = FLASH_OK;
1100
1101
1102 /*------------------------------------------------------------------------------
1103 Pre-processing
1104 ------------------------------------------------------------------------------*/
1105
1106 /* Escape to Emulator */
1107 #ifdef EMULATOR
1108 3 return emulator_flash_block_erase( flash_block_num, size );
1109 #endif
1110
1111 /* Determine block setting */
1112 switch( size )
1113 {
1114 case FLASH_BLOCK_4K:
1115 {
1116 flash_opcode = FLASH_OP_HW_4K_ERASE;
1117 flash_addr = flash_block_num*(0x1000);
1118 address_to_bytes( flash_addr, &flash_addr_bytes[0] );
1119 break;
1120 }
1121
1122 case FLASH_BLOCK_32K:
1123 {
1124 flash_opcode = FLASH_OP_HW_32K_ERASE;
1125 flash_addr = flash_block_num*(0x8000);
1126 address_to_bytes( flash_addr, &flash_addr_bytes[0] );
1127 break;
1128 }
1129
1130 case FLASH_BLOCK_64K:
1131 {
1132 flash_opcode = FLASH_OP_HW_64K_ERASE;
1133 flash_addr = flash_block_num*(0x10000);
1134 address_to_bytes( flash_addr, &flash_addr_bytes[0] );
1135
1136 /* Error check */
1137 if ( flash_block_num >= FLASH_BLOCK_8 )
1138 {
1139 return FLASH_ADDR_OUT_OF_BOUNDS;
1140 }
1141 break;
1142 }
1143 }
1144
1145 /* Check if write_enabled */
1146 if( !( write_enabled ) )
1147 {
1148 return FLASH_WRITE_PROTECTED;
1149 }
1150
1151
1152 /*------------------------------------------------------------------------------
1153 API function implementation
1154 ------------------------------------------------------------------------------*/
1155
1156 /* Enable writing to flash */
1157 flash_status = write_enable();
1158
1159 /* Sector erase sequence */
1160 HAL_GPIO_WritePin( FLASH_SS_GPIO_PORT, FLASH_SS_PIN, GPIO_PIN_RESET );
1161 hal_status[0] = HAL_SPI_Transmit( &( FLASH_SPI ) ,
1162 &flash_opcode ,
1163 sizeof( flash_opcode ),
1164 HAL_DEFAULT_TIMEOUT );
1165 hal_status[1] = HAL_SPI_Transmit( &( FLASH_SPI ) ,
1166 &flash_addr_bytes[0] ,
1167 sizeof( flash_addr_bytes ),
1168 HAL_DEFAULT_TIMEOUT );
1169 HAL_GPIO_WritePin( FLASH_SS_GPIO_PORT, FLASH_SS_PIN, GPIO_PIN_SET );
1170
1171 /* Return status code */
1172 if ( hal_status[0] != HAL_OK || hal_status[1] != HAL_OK )
1173 {
1174 return FLASH_SPI_ERROR;
1175 }
1176 else if ( flash_status != FLASH_OK )
1177 {
1178 return FLASH_FAIL;
1179 }
1180 else
1181 {
1182 return FLASH_OK;
1183 }
1184 } /* flash_block_erase */
1185
1186
1187 /*------------------------------------------------------------------------------
1188 Internal procedures
1189 ------------------------------------------------------------------------------*/
1190
1191
1192 /*******************************************************************************
1193 * *
1194 * PROCEDURE: *
1195 * address_to_bytes *
1196 * *
1197 * DESCRIPTION: *
1198 * Converts a flash memory address in uint32_t format to a byte array *
1199 * *
1200 *******************************************************************************/
1201 10700 static void address_to_bytes
1202 (
1203 uint32_t address,
1204 uint8_t* address_bytes
1205 )
1206 {
1207 10700 address_bytes[0] = (address >> 16) & 0xFF;
1208 10700 address_bytes[1] = (address >> 8 ) & 0xFF;
1209 10700 address_bytes[2] = address & 0xFF;
1210 10700 } /* address_to_bytes */
1211
1212
1213 /*******************************************************************************
1214 * *
1215 * PROCEDURE: *
1216 * bytes_to_address *
1217 * *
1218 * DESCRIPTION: *
1219 * Converts a flash memory address in byte format to uint32_t format *
1220 * *
1221 *******************************************************************************/
1222 ✗ static inline uint32_t bytes_to_address
1223 (
1224 uint8_t address_bytes[3]
1225 )
1226 {
1227 ✗ return ( (uint32_t) address_bytes[0] << 16 ) |
1228 ✗ ( (uint32_t) address_bytes[1] << 8 ) |
1229 ✗ ( (uint32_t) address_bytes[2] << 0 );
1230 } /* address_to_bytes */
1231
1232
1233 /*******************************************************************************
1234 * *
1235 * PROCEDURE: *
1236 * write_enable *
1237 * *
1238 * DESCRIPTION: *
1239 * Enable writing to the external flash chip hardware *
1240 * *
1241 *******************************************************************************/
1242 2 static FLASH_STATUS write_enable
1243 (
1244 void
1245 )
1246 {
1247 /*------------------------------------------------------------------------------
1248 Local variables
1249 ------------------------------------------------------------------------------*/
1250 2 uint8_t hal_status; /* Status code return by hal spi functions */
1251 2 uint8_t flash_opcode; /* Flash operation/instruction cyle byte */
1252
1253
1254 /*------------------------------------------------------------------------------
1255 Local variables
1256 ------------------------------------------------------------------------------*/
1257 2 hal_status = HAL_OK;
1258 2 flash_opcode = FLASH_OP_HW_WREN;
1259
1260
1261 /*------------------------------------------------------------------------------
1262 API function implementation
1263 ------------------------------------------------------------------------------*/
1264
1265 /* Send the write enable instruction to the flash over SPI */
1266 2 HAL_GPIO_WritePin( FLASH_SS_GPIO_PORT,
1267 FLASH_SS_PIN ,
1268 GPIO_PIN_RESET );
1269 2 hal_status = HAL_SPI_Transmit( &( FLASH_SPI ) ,
1270 &flash_opcode ,
1271 sizeof( flash_opcode ),
1272 HAL_DEFAULT_TIMEOUT );
1273 2 HAL_GPIO_WritePin( FLASH_SS_GPIO_PORT,
1274 FLASH_SS_PIN ,
1275 GPIO_PIN_SET );
1276
1277 /* Set write enabled bit in flash buffer handle */
1278
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if ( hal_status != HAL_OK )
1279 {
1280 return FLASH_SPI_ERROR;
1281 }
1282 else
1283 {
1284 2 return FLASH_OK;
1285 }
1286
1287 } /* write_enable */
1288
1289
1290 /*******************************************************************************
1291 * *
1292 * PROCEDURE: *
1293 * write_disable *
1294 * *
1295 * DESCRIPTION: *
1296 * Disable writing to the external flash chip hardware *
1297 * *
1298 *******************************************************************************/
1299 2 static FLASH_STATUS write_disable
1300 (
1301 void
1302 )
1303 {
1304 /*------------------------------------------------------------------------------
1305 Local variables
1306 ------------------------------------------------------------------------------*/
1307 2 uint8_t hal_status; /* Status code return by hal spi functions */
1308 2 uint8_t flash_opcode; /* Flash operation/instruction cyle byte */
1309
1310
1311 /*------------------------------------------------------------------------------
1312 Local variables
1313 ------------------------------------------------------------------------------*/
1314 2 hal_status = HAL_OK;
1315 2 flash_opcode = FLASH_OP_HW_WRDI;
1316
1317
1318 /*------------------------------------------------------------------------------
1319 API function implementation
1320 ------------------------------------------------------------------------------*/
1321
1322 /* Send the write enable instruction to the flash over SPI */
1323 2 HAL_GPIO_WritePin( FLASH_SS_GPIO_PORT,
1324 FLASH_SS_PIN ,
1325 GPIO_PIN_RESET );
1326 2 hal_status = HAL_SPI_Transmit( &( FLASH_SPI ) ,
1327 &flash_opcode ,
1328 sizeof( flash_opcode ),
1329 HAL_DEFAULT_TIMEOUT );
1330 2 HAL_GPIO_WritePin( FLASH_SS_GPIO_PORT,
1331 FLASH_SS_PIN ,
1332 GPIO_PIN_SET );
1333
1334 /* Return results of SPI HAL calls */
1335
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if ( hal_status != HAL_OK )
1336 {
1337 return FLASH_SPI_ERROR;
1338 }
1339 else
1340 {
1341 2 return FLASH_OK;
1342 }
1343
1344 } /* write_disable */
1345
1346
1347 /*******************************************************************************
1348 * END OF FILE *
1349 *******************************************************************************/
1350