diff --git a/Blocks/General_Blocks/spi/alhambra_ii/spi_controller/Icestudio/Example.ice b/Blocks/General_Blocks/spi/alhambra_ii/spi_controller/Icestudio/Example.ice new file mode 100644 index 00000000..a9a818a4 --- /dev/null +++ b/Blocks/General_Blocks/spi/alhambra_ii/spi_controller/Icestudio/Example.ice @@ -0,0 +1,1676 @@ +{ + "version": "1.2", + "package": { + "name": "ov7670_rgb_yuv", + "version": "1.1", + "description": "Configures ov7670 in either RGB444 or YUV and shows it", + "author": "Felipe Machado", + "image": "" + }, + "design": { + "board": "alhambra-ii", + "graph": { + "blocks": [ + { + "id": "5762721f-d258-4a65-8e56-b9e74c98972a", + "type": "basic.output", + "data": { + "name": "ss", + "pins": [ + { + "index": "0", + "name": "D4", + "value": "8" + } + ], + "virtual": false + }, + "position": { + "x": 568, + "y": -440 + } + }, + { + "id": "629f8b48-a6c0-4bd0-b04e-9bc99d550f5f", + "type": "basic.input", + "data": { + "name": "rst", + "pins": [ + { + "index": "0", + "name": "SW1", + "value": "34" + } + ], + "virtual": false, + "clock": false + }, + "position": { + "x": -176, + "y": -424 + } + }, + { + "id": "408c4263-1fd9-477e-866e-b522753745e4", + "type": "basic.output", + "data": { + "name": "sclk", + "pins": [ + { + "index": "0", + "name": "D0", + "value": "2" + } + ], + "virtual": false + }, + "position": { + "x": 1120, + "y": -288 + } + }, + { + "id": "39dbf40a-f91e-47a8-82ff-4f76416acabf", + "type": "basic.output", + "data": { + "name": "mosi_o", + "pins": [ + { + "index": "0", + "name": "D2", + "value": "4" + } + ], + "virtual": false + }, + "position": { + "x": 1112, + "y": -200 + } + }, + { + "id": "5d4099f3-f1ad-4f9f-8076-9e27369c9b9e", + "type": "basic.output", + "data": { + "name": "rpi_running", + "pins": [ + { + "index": "0", + "name": "D3", + "value": "3" + } + ], + "virtual": false + }, + "position": { + "x": 1112, + "y": -112 + } + }, + { + "id": "7a55fc31-5d15-4bca-8b14-93101f389387", + "type": "basic.input", + "data": { + "name": "miso", + "pins": [ + { + "index": "0", + "name": "D1", + "value": "1" + } + ], + "virtual": false, + "clock": false + }, + "position": { + "x": 808, + "y": 72 + } + }, + { + "id": "2dc732a5-b189-4835-bd8b-81594ce2f640", + "type": "1e3e2fe589ecba428455b3f167a8e84edb4c218b", + "position": { + "x": 352, + "y": -328 + }, + "size": { + "width": 96, + "height": 288 + } + }, + { + "id": "2e4462be-a255-413e-bfcf-be22fb521a8d", + "type": "2efe39da646c359984049ea063338769e484bb63", + "position": { + "x": 912, + "y": -360 + }, + "size": { + "width": 96, + "height": 224 + } + }, + { + "id": "fed6a17d-60da-421c-bf3b-e490c6ac5d71", + "type": "basic.code", + "data": { + "code": "assign vel = 8'd40;", + "params": [], + "ports": { + "in": [], + "out": [ + { + "name": "vel", + "range": "[7:0]", + "size": 8 + } + ] + } + }, + "position": { + "x": -192, + "y": -296 + }, + "size": { + "width": 232, + "height": 64 + } + }, + { + "id": "6d96d919-f5fc-49f3-9aa1-4ace6ae960ee", + "type": "basic.code", + "data": { + "code": "assign led = 24'hff0000;", + "params": [], + "ports": { + "in": [], + "out": [ + { + "name": "led", + "range": "[23:0]", + "size": 24 + } + ] + } + }, + "position": { + "x": -200, + "y": -176 + }, + "size": { + "width": 232, + "height": 64 + } + } + ], + "wires": [ + { + "source": { + "block": "629f8b48-a6c0-4bd0-b04e-9bc99d550f5f", + "port": "out" + }, + "target": { + "block": "2dc732a5-b189-4835-bd8b-81594ce2f640", + "port": "fff8810d-4cef-42d3-8896-8c9e4a496379" + }, + "vertices": [ + { + "x": 0, + "y": -344 + } + ] + }, + { + "source": { + "block": "629f8b48-a6c0-4bd0-b04e-9bc99d550f5f", + "port": "out" + }, + "target": { + "block": "2e4462be-a255-413e-bfcf-be22fb521a8d", + "port": "cfbf8498-f0bc-4fb0-bc44-1a03a9e83e9c" + }, + "vertices": [ + { + "x": 656, + "y": -312 + } + ] + }, + { + "source": { + "block": "2dc732a5-b189-4835-bd8b-81594ce2f640", + "port": "e86e026a-227d-4bf8-8c70-53ea31e04a3c" + }, + "target": { + "block": "2e4462be-a255-413e-bfcf-be22fb521a8d", + "port": "f19e3f2e-32c6-4629-942e-f88704750d9d" + }, + "vertices": [ + { + "x": 632, + "y": -192 + } + ] + }, + { + "source": { + "block": "2dc732a5-b189-4835-bd8b-81594ce2f640", + "port": "d34cf187-214e-4ae8-9603-3c41146647e3" + }, + "target": { + "block": "2e4462be-a255-413e-bfcf-be22fb521a8d", + "port": "fd93ee0e-cc6f-4386-8d45-28d9ac257767" + }, + "vertices": [ + { + "x": 672, + "y": -248 + } + ] + }, + { + "source": { + "block": "2dc732a5-b189-4835-bd8b-81594ce2f640", + "port": "bbd54035-423d-4fa2-82ca-59b83d57b3e9" + }, + "target": { + "block": "2e4462be-a255-413e-bfcf-be22fb521a8d", + "port": "7c071aa2-1f78-462c-bbf1-b07283922ed1" + }, + "vertices": [ + { + "x": 664, + "y": -112 + } + ], + "size": 8 + }, + { + "source": { + "block": "2e4462be-a255-413e-bfcf-be22fb521a8d", + "port": "fdc0b9ae-45ae-4285-86c8-6f8a66d97fb6" + }, + "target": { + "block": "2dc732a5-b189-4835-bd8b-81594ce2f640", + "port": "a9a0f2c3-60e8-49c7-90c8-ee81b695e8a4" + }, + "vertices": [ + { + "x": 480, + "y": -496 + }, + { + "x": 288, + "y": -464 + } + ] + }, + { + "source": { + "block": "2e4462be-a255-413e-bfcf-be22fb521a8d", + "port": "50e235e2-3385-4dc2-869c-a29a300b39be" + }, + "target": { + "block": "408c4263-1fd9-477e-866e-b522753745e4", + "port": "in" + } + }, + { + "source": { + "block": "2e4462be-a255-413e-bfcf-be22fb521a8d", + "port": "3518615b-f740-4450-b702-e0eddcdcb7e4" + }, + "target": { + "block": "39dbf40a-f91e-47a8-82ff-4f76416acabf", + "port": "in" + } + }, + { + "source": { + "block": "2e4462be-a255-413e-bfcf-be22fb521a8d", + "port": "3f8d97c2-b88b-4c8d-b717-480bf7b36b52" + }, + "target": { + "block": "5d4099f3-f1ad-4f9f-8076-9e27369c9b9e", + "port": "in" + } + }, + { + "source": { + "block": "2dc732a5-b189-4835-bd8b-81594ce2f640", + "port": "50262b52-dd70-4386-94f6-b41d4259401d" + }, + "target": { + "block": "5762721f-d258-4a65-8e56-b9e74c98972a", + "port": "in" + } + }, + { + "source": { + "block": "7a55fc31-5d15-4bca-8b14-93101f389387", + "port": "out" + }, + "target": { + "block": "2e4462be-a255-413e-bfcf-be22fb521a8d", + "port": "6fd30186-e930-4605-8b97-b02c1302684e" + } + }, + { + "source": { + "block": "6d96d919-f5fc-49f3-9aa1-4ace6ae960ee", + "port": "led" + }, + "target": { + "block": "2dc732a5-b189-4835-bd8b-81594ce2f640", + "port": "e20802df-0fbb-48e6-b5d4-89a3ab66a171" + }, + "size": 24 + }, + { + "source": { + "block": "fed6a17d-60da-421c-bf3b-e490c6ac5d71", + "port": "vel" + }, + "target": { + "block": "2dc732a5-b189-4835-bd8b-81594ce2f640", + "port": "bbc89353-68a5-4b76-8fbb-c196bdaf2dde" + }, + "size": 8 + } + ] + } + }, + "dependencies": { + "1e3e2fe589ecba428455b3f167a8e84edb4c218b": { + "package": { + "name": "GPG Control ", + "version": "", + "description": "", + "author": "rnicklas", + "image": "" + }, + "design": { + "graph": { + "blocks": [ + { + "id": "fff8810d-4cef-42d3-8896-8c9e4a496379", + "type": "basic.input", + "data": { + "name": "rst", + "clock": false + }, + "position": { + "x": -120, + "y": 144 + } + }, + { + "id": "50262b52-dd70-4386-94f6-b41d4259401d", + "type": "basic.output", + "data": { + "name": "spi_ss_n", + "virtual": false + }, + "position": { + "x": 832, + "y": 176 + } + }, + { + "id": "5db2bf01-b245-4887-b6bd-5c20bcc01c8b", + "type": "basic.input", + "data": { + "name": "clk", + "clock": true + }, + "position": { + "x": -120, + "y": 200 + } + }, + { + "id": "a9a0f2c3-60e8-49c7-90c8-ee81b695e8a4", + "type": "basic.input", + "data": { + "name": "busy_spi", + "clock": false + }, + "position": { + "x": -120, + "y": 248 + } + }, + { + "id": "d34cf187-214e-4ae8-9603-3c41146647e3", + "type": "basic.output", + "data": { + "name": "spi_send", + "virtual": false + }, + "position": { + "x": 824, + "y": 296 + } + }, + { + "id": "bbc89353-68a5-4b76-8fbb-c196bdaf2dde", + "type": "basic.input", + "data": { + "name": "motor_pwm_left_i", + "range": "[7:0]", + "pins": [ + { + "index": "7", + "name": "", + "value": "" + }, + { + "index": "6", + "name": "", + "value": "" + }, + { + "index": "5", + "name": "", + "value": "" + }, + { + "index": "4", + "name": "", + "value": "" + }, + { + "index": "3", + "name": "", + "value": "" + }, + { + "index": "2", + "name": "", + "value": "" + }, + { + "index": "1", + "name": "", + "value": "" + }, + { + "index": "0", + "name": "", + "value": "" + } + ], + "virtual": false, + "clock": false + }, + "position": { + "x": -120, + "y": 304 + } + }, + { + "id": "3c1f8a9d-1ff2-4dd1-8c1f-ba07ef274c80", + "type": "basic.input", + "data": { + "name": "motor_pwm_rght_i", + "range": "[7:0]", + "pins": [ + { + "index": "7", + "name": "", + "value": "" + }, + { + "index": "6", + "name": "", + "value": "" + }, + { + "index": "5", + "name": "", + "value": "" + }, + { + "index": "4", + "name": "", + "value": "" + }, + { + "index": "3", + "name": "", + "value": "" + }, + { + "index": "2", + "name": "", + "value": "" + }, + { + "index": "1", + "name": "", + "value": "" + }, + { + "index": "0", + "name": "", + "value": "" + } + ], + "virtual": false, + "clock": false + }, + "position": { + "x": -128, + "y": 360 + } + }, + { + "id": "e86e026a-227d-4bf8-8c70-53ea31e04a3c", + "type": "basic.output", + "data": { + "name": "ena_2clk" + }, + "position": { + "x": 824, + "y": 416 + } + }, + { + "id": "0395c4a7-859a-4bee-94a6-9a2642c9606e", + "type": "basic.input", + "data": { + "name": "led_eye_left_rgb_i", + "range": "[23:0]", + "pins": [ + { + "index": "23", + "name": "", + "value": "" + }, + { + "index": "22", + "name": "", + "value": "" + }, + { + "index": "21", + "name": "", + "value": "" + }, + { + "index": "20", + "name": "", + "value": "" + }, + { + "index": "19", + "name": "", + "value": "" + }, + { + "index": "18", + "name": "", + "value": "" + }, + { + "index": "17", + "name": "", + "value": "" + }, + { + "index": "16", + "name": "", + "value": "" + }, + { + "index": "15", + "name": "", + "value": "" + }, + { + "index": "14", + "name": "", + "value": "" + }, + { + "index": "13", + "name": "", + "value": "" + }, + { + "index": "12", + "name": "", + "value": "" + }, + { + "index": "11", + "name": "", + "value": "" + }, + { + "index": "10", + "name": "", + "value": "" + }, + { + "index": "9", + "name": "", + "value": "" + }, + { + "index": "8", + "name": "", + "value": "" + }, + { + "index": "7", + "name": "", + "value": "" + }, + { + "index": "6", + "name": "", + "value": "" + }, + { + "index": "5", + "name": "", + "value": "" + }, + { + "index": "4", + "name": "", + "value": "" + }, + { + "index": "3", + "name": "", + "value": "" + }, + { + "index": "2", + "name": "", + "value": "" + }, + { + "index": "1", + "name": "", + "value": "" + }, + { + "index": "0", + "name": "", + "value": "" + } + ], + "virtual": false, + "clock": false + }, + "position": { + "x": -136, + "y": 416 + } + }, + { + "id": "e6c85cad-f473-4ceb-8de7-9a58743709bc", + "type": "basic.input", + "data": { + "name": "led_eye_rght_rgb_i", + "range": "[23:0]", + "pins": [ + { + "index": "23", + "name": "", + "value": "" + }, + { + "index": "22", + "name": "", + "value": "" + }, + { + "index": "21", + "name": "", + "value": "" + }, + { + "index": "20", + "name": "", + "value": "" + }, + { + "index": "19", + "name": "", + "value": "" + }, + { + "index": "18", + "name": "", + "value": "" + }, + { + "index": "17", + "name": "", + "value": "" + }, + { + "index": "16", + "name": "", + "value": "" + }, + { + "index": "15", + "name": "", + "value": "" + }, + { + "index": "14", + "name": "", + "value": "" + }, + { + "index": "13", + "name": "", + "value": "" + }, + { + "index": "12", + "name": "", + "value": "" + }, + { + "index": "11", + "name": "", + "value": "" + }, + { + "index": "10", + "name": "", + "value": "" + }, + { + "index": "9", + "name": "", + "value": "" + }, + { + "index": "8", + "name": "", + "value": "" + }, + { + "index": "7", + "name": "", + "value": "" + }, + { + "index": "6", + "name": "", + "value": "" + }, + { + "index": "5", + "name": "", + "value": "" + }, + { + "index": "4", + "name": "", + "value": "" + }, + { + "index": "3", + "name": "", + "value": "" + }, + { + "index": "2", + "name": "", + "value": "" + }, + { + "index": "1", + "name": "", + "value": "" + }, + { + "index": "0", + "name": "", + "value": "" + } + ], + "virtual": false, + "clock": false + }, + "position": { + "x": -136, + "y": 464 + } + }, + { + "id": "065ed119-dca7-4790-b4a1-f6ffe79050ca", + "type": "basic.input", + "data": { + "name": "led_blink_left_rgb_i", + "range": "[23:0]", + "pins": [ + { + "index": "23", + "name": "", + "value": "" + }, + { + "index": "22", + "name": "", + "value": "" + }, + { + "index": "21", + "name": "", + "value": "" + }, + { + "index": "20", + "name": "", + "value": "" + }, + { + "index": "19", + "name": "", + "value": "" + }, + { + "index": "18", + "name": "", + "value": "" + }, + { + "index": "17", + "name": "", + "value": "" + }, + { + "index": "16", + "name": "", + "value": "" + }, + { + "index": "15", + "name": "", + "value": "" + }, + { + "index": "14", + "name": "", + "value": "" + }, + { + "index": "13", + "name": "", + "value": "" + }, + { + "index": "12", + "name": "", + "value": "" + }, + { + "index": "11", + "name": "", + "value": "" + }, + { + "index": "10", + "name": "", + "value": "" + }, + { + "index": "9", + "name": "", + "value": "" + }, + { + "index": "8", + "name": "", + "value": "" + }, + { + "index": "7", + "name": "", + "value": "" + }, + { + "index": "6", + "name": "", + "value": "" + }, + { + "index": "5", + "name": "", + "value": "" + }, + { + "index": "4", + "name": "", + "value": "" + }, + { + "index": "3", + "name": "", + "value": "" + }, + { + "index": "2", + "name": "", + "value": "" + }, + { + "index": "1", + "name": "", + "value": "" + }, + { + "index": "0", + "name": "", + "value": "" + } + ], + "virtual": false, + "clock": false + }, + "position": { + "x": -136, + "y": 512 + } + }, + { + "id": "bbd54035-423d-4fa2-82ca-59b83d57b3e9", + "type": "basic.output", + "data": { + "name": "data_spi", + "range": "[7:0]", + "size": 8 + }, + "position": { + "x": 832, + "y": 536 + } + }, + { + "id": "e20802df-0fbb-48e6-b5d4-89a3ab66a171", + "type": "basic.input", + "data": { + "name": "led_blink_rght_rgb_i", + "range": "[23:0]", + "pins": [ + { + "index": "23", + "name": "", + "value": "" + }, + { + "index": "22", + "name": "", + "value": "" + }, + { + "index": "21", + "name": "", + "value": "" + }, + { + "index": "20", + "name": "", + "value": "" + }, + { + "index": "19", + "name": "", + "value": "" + }, + { + "index": "18", + "name": "", + "value": "" + }, + { + "index": "17", + "name": "", + "value": "" + }, + { + "index": "16", + "name": "", + "value": "" + }, + { + "index": "15", + "name": "", + "value": "" + }, + { + "index": "14", + "name": "", + "value": "" + }, + { + "index": "13", + "name": "", + "value": "" + }, + { + "index": "12", + "name": "", + "value": "" + }, + { + "index": "11", + "name": "", + "value": "" + }, + { + "index": "10", + "name": "", + "value": "" + }, + { + "index": "9", + "name": "", + "value": "" + }, + { + "index": "8", + "name": "", + "value": "" + }, + { + "index": "7", + "name": "", + "value": "" + }, + { + "index": "6", + "name": "", + "value": "" + }, + { + "index": "5", + "name": "", + "value": "" + }, + { + "index": "4", + "name": "", + "value": "" + }, + { + "index": "3", + "name": "", + "value": "" + }, + { + "index": "2", + "name": "", + "value": "" + }, + { + "index": "1", + "name": "", + "value": "" + }, + { + "index": "0", + "name": "", + "value": "" + } + ], + "virtual": false, + "clock": false + }, + "position": { + "x": -136, + "y": 560 + } + }, + { + "id": "b4e7bdea-88b7-4a43-a26d-f3cde8c7a4e2", + "type": "basic.code", + "data": { + "code": "// @include spi_ledctrl.v\r\n\r\n spi_ledctrl i_spi_ledctrl\r\n (\r\n .rst (rst),\r\n .clk (clk),\r\n .busy_spi (busy_spi),\r\n .motor_pwm_left_i (motor_pwm_left_i),\r\n .motor_pwm_rght_i (motor_pwm_rght_i),\r\n .led_eye_left_rgb_i (led_eye_left_rgb_i),\r\n .led_eye_rght_rgb_i (led_eye_rght_rgb_i),\r\n .led_blink_left_rgb_i (led_blink_left_rgb_i),\r\n .led_blink_rght_rgb_i (led_blink_rght_rgb_i),\r\n .spi_ss_n (spi_ss_n), // spi slave select\r\n .spi_send (spi_send),\r\n .ena_2clk (ena_2clk),\r\n .data_spi (data_spi)\r\n );\r\n", + "params": [], + "ports": { + "in": [ + { + "name": "rst" + }, + { + "name": "clk" + }, + { + "name": "busy_spi" + }, + { + "name": "motor_pwm_left_i", + "range": "[7:0]", + "size": 8 + }, + { + "name": "motor_pwm_rght_i", + "range": "[7:0]", + "size": 8 + }, + { + "name": "led_eye_left_rgb_i", + "range": "[23:0]", + "size": 24 + }, + { + "name": "led_eye_rght_rgb_i", + "range": "[23:0]", + "size": 24 + }, + { + "name": "led_blink_left_rgb_i", + "range": "[23:0]", + "size": 24 + }, + { + "name": "led_blink_rght_rgb_i", + "range": "[23:0]", + "size": 24 + } + ], + "out": [ + { + "name": "spi_ss_n" + }, + { + "name": "spi_send" + }, + { + "name": "ena_2clk" + }, + { + "name": "data_spi", + "range": "[7:0]", + "size": 8 + } + ] + } + }, + "position": { + "x": 192, + "y": 152 + }, + "size": { + "width": 552, + "height": 472 + } + } + ], + "wires": [ + { + "source": { + "block": "5db2bf01-b245-4887-b6bd-5c20bcc01c8b", + "port": "out" + }, + "target": { + "block": "b4e7bdea-88b7-4a43-a26d-f3cde8c7a4e2", + "port": "clk" + } + }, + { + "source": { + "block": "fff8810d-4cef-42d3-8896-8c9e4a496379", + "port": "out" + }, + "target": { + "block": "b4e7bdea-88b7-4a43-a26d-f3cde8c7a4e2", + "port": "rst" + } + }, + { + "source": { + "block": "a9a0f2c3-60e8-49c7-90c8-ee81b695e8a4", + "port": "out" + }, + "target": { + "block": "b4e7bdea-88b7-4a43-a26d-f3cde8c7a4e2", + "port": "busy_spi" + } + }, + { + "source": { + "block": "b4e7bdea-88b7-4a43-a26d-f3cde8c7a4e2", + "port": "ena_2clk" + }, + "target": { + "block": "e86e026a-227d-4bf8-8c70-53ea31e04a3c", + "port": "in" + } + }, + { + "source": { + "block": "b4e7bdea-88b7-4a43-a26d-f3cde8c7a4e2", + "port": "data_spi" + }, + "target": { + "block": "bbd54035-423d-4fa2-82ca-59b83d57b3e9", + "port": "in" + }, + "size": 8 + }, + { + "source": { + "block": "b4e7bdea-88b7-4a43-a26d-f3cde8c7a4e2", + "port": "spi_send" + }, + "target": { + "block": "d34cf187-214e-4ae8-9603-3c41146647e3", + "port": "in" + } + }, + { + "source": { + "block": "b4e7bdea-88b7-4a43-a26d-f3cde8c7a4e2", + "port": "spi_ss_n" + }, + "target": { + "block": "50262b52-dd70-4386-94f6-b41d4259401d", + "port": "in" + } + }, + { + "source": { + "block": "bbc89353-68a5-4b76-8fbb-c196bdaf2dde", + "port": "out" + }, + "target": { + "block": "b4e7bdea-88b7-4a43-a26d-f3cde8c7a4e2", + "port": "motor_pwm_left_i" + }, + "size": 8 + }, + { + "source": { + "block": "3c1f8a9d-1ff2-4dd1-8c1f-ba07ef274c80", + "port": "out" + }, + "target": { + "block": "b4e7bdea-88b7-4a43-a26d-f3cde8c7a4e2", + "port": "motor_pwm_rght_i" + }, + "size": 8 + }, + { + "source": { + "block": "0395c4a7-859a-4bee-94a6-9a2642c9606e", + "port": "out" + }, + "target": { + "block": "b4e7bdea-88b7-4a43-a26d-f3cde8c7a4e2", + "port": "led_eye_left_rgb_i" + }, + "size": 24 + }, + { + "source": { + "block": "e6c85cad-f473-4ceb-8de7-9a58743709bc", + "port": "out" + }, + "target": { + "block": "b4e7bdea-88b7-4a43-a26d-f3cde8c7a4e2", + "port": "led_eye_rght_rgb_i" + }, + "size": 24 + }, + { + "source": { + "block": "065ed119-dca7-4790-b4a1-f6ffe79050ca", + "port": "out" + }, + "target": { + "block": "b4e7bdea-88b7-4a43-a26d-f3cde8c7a4e2", + "port": "led_blink_left_rgb_i" + }, + "size": 24 + }, + { + "source": { + "block": "e20802df-0fbb-48e6-b5d4-89a3ab66a171", + "port": "out" + }, + "target": { + "block": "b4e7bdea-88b7-4a43-a26d-f3cde8c7a4e2", + "port": "led_blink_rght_rgb_i" + }, + "size": 24 + } + ] + } + } + }, + "2efe39da646c359984049ea063338769e484bb63": { + "package": { + "name": "", + "version": "", + "description": "", + "author": "", + "image": "" + }, + "design": { + "graph": { + "blocks": [ + { + "id": "e7cb9381-4164-4c25-ba00-72c37df2df31", + "type": "basic.input", + "data": { + "name": "clk", + "clock": true + }, + "position": { + "x": -176, + "y": 136 + } + }, + { + "id": "fdc0b9ae-45ae-4285-86c8-6f8a66d97fb6", + "type": "basic.output", + "data": { + "name": "busy_spi" + }, + "position": { + "x": 904, + "y": 144 + } + }, + { + "id": "cfbf8498-f0bc-4fb0-bc44-1a03a9e83e9c", + "type": "basic.input", + "data": { + "name": "rst", + "clock": false + }, + "position": { + "x": -200, + "y": 184 + } + }, + { + "id": "f19e3f2e-32c6-4629-942e-f88704750d9d", + "type": "basic.input", + "data": { + "name": "ena_2clk", + "clock": false + }, + "position": { + "x": -200, + "y": 240 + } + }, + { + "id": "fd93ee0e-cc6f-4386-8d45-28d9ac257767", + "type": "basic.input", + "data": { + "name": "start", + "clock": false + }, + "position": { + "x": -216, + "y": 304 + } + }, + { + "id": "50e235e2-3385-4dc2-869c-a29a300b39be", + "type": "basic.output", + "data": { + "name": "sclk_o" + }, + "position": { + "x": 920, + "y": 328 + } + }, + { + "id": "7c071aa2-1f78-462c-bbf1-b07283922ed1", + "type": "basic.input", + "data": { + "name": "data_spi", + "range": "[7:0]", + "clock": false, + "size": 8 + }, + "position": { + "x": -208, + "y": 384 + } + }, + { + "id": "af6f65e2-a2a6-49c8-a6d7-f27154f3cc76", + "type": "basic.input", + "data": { + "name": "ack", + "clock": false + }, + "position": { + "x": -56, + "y": 456 + } + }, + { + "id": "3518615b-f740-4450-b702-e0eddcdcb7e4", + "type": "basic.output", + "data": { + "name": "mosi_o" + }, + "position": { + "x": 912, + "y": 480 + } + }, + { + "id": "3f8d97c2-b88b-4c8d-b717-480bf7b36b52", + "type": "basic.output", + "data": { + "name": "rpi_run" + }, + "position": { + "x": 856, + "y": 552 + } + }, + { + "id": "6fd30186-e930-4605-8b97-b02c1302684e", + "type": "basic.input", + "data": { + "name": "miso_i", + "clock": false + }, + "position": { + "x": -216, + "y": 576 + } + }, + { + "id": "686efab2-218f-40e8-a203-454f35652261", + "type": "basic.code", + "data": { + "code": "// @include spi_master.v\r\n \r\n SPI_Master i_spi_master\r\n (\r\n // System\r\n .clk_i (clk),\r\n .rst_i (rst),\r\n .ena_i (ena_2clk), // 2*SCK\r\n // Interface\r\n .start_i (start),\r\n .ack_i (ack), // IRQ Ack\r\n .tx_i (data_spi),\r\n .busy_o (busy_spi), \r\n\r\n // SPI\r\n .sclk_o (sclk_o), \r\n .miso_i (miso_i),\r\n //.mosi_en_o (ssb), \r\n .mosi_o (mosi_o),\r\n .rpi_running (rpi_running)\r\n );\r\n", + "params": [], + "ports": { + "in": [ + { + "name": "clk" + }, + { + "name": "rst" + }, + { + "name": "ena_2clk" + }, + { + "name": "start" + }, + { + "name": "data_spi", + "range": "[7:0]", + "size": 8 + }, + { + "name": "ack" + }, + { + "name": "miso_i" + } + ], + "out": [ + { + "name": "busy_spi" + }, + { + "name": "sclk_o" + }, + { + "name": "mosi_o" + }, + { + "name": "rpi_running" + } + ] + } + }, + "position": { + "x": 208, + "y": 144 + }, + "size": { + "width": 544, + "height": 448 + } + } + ], + "wires": [ + { + "source": { + "block": "e7cb9381-4164-4c25-ba00-72c37df2df31", + "port": "out" + }, + "target": { + "block": "686efab2-218f-40e8-a203-454f35652261", + "port": "clk" + } + }, + { + "source": { + "block": "cfbf8498-f0bc-4fb0-bc44-1a03a9e83e9c", + "port": "out" + }, + "target": { + "block": "686efab2-218f-40e8-a203-454f35652261", + "port": "rst" + } + }, + { + "source": { + "block": "f19e3f2e-32c6-4629-942e-f88704750d9d", + "port": "out" + }, + "target": { + "block": "686efab2-218f-40e8-a203-454f35652261", + "port": "ena_2clk" + } + }, + { + "source": { + "block": "fd93ee0e-cc6f-4386-8d45-28d9ac257767", + "port": "out" + }, + "target": { + "block": "686efab2-218f-40e8-a203-454f35652261", + "port": "start" + } + }, + { + "source": { + "block": "7c071aa2-1f78-462c-bbf1-b07283922ed1", + "port": "out" + }, + "target": { + "block": "686efab2-218f-40e8-a203-454f35652261", + "port": "data_spi" + }, + "vertices": [ + { + "x": -56, + "y": 368 + } + ], + "size": 8 + }, + { + "source": { + "block": "af6f65e2-a2a6-49c8-a6d7-f27154f3cc76", + "port": "out" + }, + "target": { + "block": "686efab2-218f-40e8-a203-454f35652261", + "port": "ack" + } + }, + { + "source": { + "block": "6fd30186-e930-4605-8b97-b02c1302684e", + "port": "out" + }, + "target": { + "block": "686efab2-218f-40e8-a203-454f35652261", + "port": "miso_i" + } + }, + { + "source": { + "block": "686efab2-218f-40e8-a203-454f35652261", + "port": "busy_spi" + }, + "target": { + "block": "fdc0b9ae-45ae-4285-86c8-6f8a66d97fb6", + "port": "in" + } + }, + { + "source": { + "block": "686efab2-218f-40e8-a203-454f35652261", + "port": "sclk_o" + }, + "target": { + "block": "50e235e2-3385-4dc2-869c-a29a300b39be", + "port": "in" + } + }, + { + "source": { + "block": "686efab2-218f-40e8-a203-454f35652261", + "port": "mosi_o" + }, + "target": { + "block": "3518615b-f740-4450-b702-e0eddcdcb7e4", + "port": "in" + } + }, + { + "source": { + "block": "686efab2-218f-40e8-a203-454f35652261", + "port": "rpi_running" + }, + "target": { + "block": "3f8d97c2-b88b-4c8d-b717-480bf7b36b52", + "port": "in" + } + } + ] + } + } + } + } +} \ No newline at end of file diff --git a/Blocks/General_Blocks/spi/alhambra_ii/spi_controller/Icestudio/spi_ctrl.ice b/Blocks/General_Blocks/spi/alhambra_ii/spi_controller/Icestudio/spi_ctrl.ice new file mode 100644 index 00000000..5d899c40 --- /dev/null +++ b/Blocks/General_Blocks/spi/alhambra_ii/spi_controller/Icestudio/spi_ctrl.ice @@ -0,0 +1,1060 @@ +{ + "version": "1.2", + "package": { + "name": "GoPiGo Controller ", + "version": "1.0", + "description": "", + "author": "JdeRobot", + "image": "" + }, + "design": { + "board": "alhambra-ii", + "graph": { + "blocks": [ + { + "id": "7be2ddb1-d6a1-4bd7-ae61-39bfb790c83a", + "type": "basic.input", + "data": { + "name": "rst", + "pins": [ + { + "index": "0", + "name": "", + "value": "" + } + ], + "virtual": true, + "clock": false + }, + "position": { + "x": 96, + "y": 208 + } + }, + { + "id": "69dc2722-2a9d-4126-b109-7e31cfea16b6", + "type": "basic.output", + "data": { + "name": "spi_ss_n", + "pins": [ + { + "index": "0", + "name": "", + "value": "" + } + ], + "virtual": true + }, + "position": { + "x": 968, + "y": 224 + } + }, + { + "id": "a1e8c8a0-be11-4a4d-a19e-f8ee03fa17ae", + "type": "basic.input", + "data": { + "name": "clk", + "pins": [ + { + "index": "0", + "name": "", + "value": "" + } + ], + "virtual": true, + "clock": true + }, + "position": { + "x": -40, + "y": 256 + } + }, + { + "id": "27b9b159-fff3-4aa8-a549-d95bf7cffa35", + "type": "basic.input", + "data": { + "name": "busy_spi", + "pins": [ + { + "index": "0", + "name": "", + "value": "" + } + ], + "virtual": true, + "clock": false + }, + "position": { + "x": 88, + "y": 296 + } + }, + { + "id": "252056ef-9e93-4572-9542-6c05ab5014f3", + "type": "basic.output", + "data": { + "name": "spi_send", + "pins": [ + { + "index": "0", + "name": "", + "value": "" + } + ], + "virtual": true + }, + "position": { + "x": 984, + "y": 344 + } + }, + { + "id": "30efe8a5-78b5-4d54-9240-38fe50b23cf7", + "type": "basic.input", + "data": { + "name": "motor_pwm_left_i", + "range": "[7:0]", + "pins": [ + { + "index": "7", + "name": "", + "value": "" + }, + { + "index": "6", + "name": "", + "value": "" + }, + { + "index": "5", + "name": "", + "value": "" + }, + { + "index": "4", + "name": "", + "value": "" + }, + { + "index": "3", + "name": "", + "value": "" + }, + { + "index": "2", + "name": "", + "value": "" + }, + { + "index": "1", + "name": "", + "value": "" + }, + { + "index": "0", + "name": "", + "value": "" + } + ], + "virtual": true, + "clock": false + }, + "position": { + "x": -96, + "y": 352 + } + }, + { + "id": "d9089370-ca82-4916-a658-332acf5559d7", + "type": "basic.input", + "data": { + "name": "motor_pwm_rght_i", + "range": "[7:0]", + "pins": [ + { + "index": "7", + "name": "", + "value": "" + }, + { + "index": "6", + "name": "", + "value": "" + }, + { + "index": "5", + "name": "", + "value": "" + }, + { + "index": "4", + "name": "", + "value": "" + }, + { + "index": "3", + "name": "", + "value": "" + }, + { + "index": "2", + "name": "", + "value": "" + }, + { + "index": "1", + "name": "", + "value": "" + }, + { + "index": "0", + "name": "", + "value": "" + } + ], + "virtual": true, + "clock": false + }, + "position": { + "x": -96, + "y": 400 + } + }, + { + "id": "76d276fd-4d90-4f03-8e17-82b1cebc95b0", + "type": "basic.input", + "data": { + "name": "led_eye_left_rgb_i", + "range": "[23:0]", + "pins": [ + { + "index": "23", + "name": "", + "value": "" + }, + { + "index": "22", + "name": "", + "value": "" + }, + { + "index": "21", + "name": "", + "value": "" + }, + { + "index": "20", + "name": "", + "value": "" + }, + { + "index": "19", + "name": "", + "value": "" + }, + { + "index": "18", + "name": "", + "value": "" + }, + { + "index": "17", + "name": "", + "value": "" + }, + { + "index": "16", + "name": "", + "value": "" + }, + { + "index": "15", + "name": "", + "value": "" + }, + { + "index": "14", + "name": "", + "value": "" + }, + { + "index": "13", + "name": "", + "value": "" + }, + { + "index": "12", + "name": "", + "value": "" + }, + { + "index": "11", + "name": "", + "value": "" + }, + { + "index": "10", + "name": "", + "value": "" + }, + { + "index": "9", + "name": "", + "value": "" + }, + { + "index": "8", + "name": "", + "value": "" + }, + { + "index": "7", + "name": "", + "value": "" + }, + { + "index": "6", + "name": "", + "value": "" + }, + { + "index": "5", + "name": "", + "value": "" + }, + { + "index": "4", + "name": "", + "value": "" + }, + { + "index": "3", + "name": "", + "value": "" + }, + { + "index": "2", + "name": "", + "value": "" + }, + { + "index": "1", + "name": "", + "value": "" + }, + { + "index": "0", + "name": "", + "value": "" + } + ], + "virtual": true, + "clock": false + }, + "position": { + "x": -104, + "y": 456 + } + }, + { + "id": "a4ff0e57-8710-43bd-84f6-c41eded90435", + "type": "basic.output", + "data": { + "name": "ena_2clk", + "pins": [ + { + "index": "0", + "name": "", + "value": "" + } + ], + "virtual": true + }, + "position": { + "x": 960, + "y": 464 + } + }, + { + "id": "653def34-7abb-4924-8f15-8e326f02964e", + "type": "basic.input", + "data": { + "name": "led_eye_rght_rgb_i", + "range": "[23:0]", + "pins": [ + { + "index": "23", + "name": "", + "value": "" + }, + { + "index": "22", + "name": "", + "value": "" + }, + { + "index": "21", + "name": "", + "value": "" + }, + { + "index": "20", + "name": "", + "value": "" + }, + { + "index": "19", + "name": "", + "value": "" + }, + { + "index": "18", + "name": "", + "value": "" + }, + { + "index": "17", + "name": "", + "value": "" + }, + { + "index": "16", + "name": "", + "value": "" + }, + { + "index": "15", + "name": "", + "value": "" + }, + { + "index": "14", + "name": "", + "value": "" + }, + { + "index": "13", + "name": "", + "value": "" + }, + { + "index": "12", + "name": "", + "value": "" + }, + { + "index": "11", + "name": "", + "value": "" + }, + { + "index": "10", + "name": "", + "value": "" + }, + { + "index": "9", + "name": "", + "value": "" + }, + { + "index": "8", + "name": "", + "value": "" + }, + { + "index": "7", + "name": "", + "value": "" + }, + { + "index": "6", + "name": "", + "value": "" + }, + { + "index": "5", + "name": "", + "value": "" + }, + { + "index": "4", + "name": "", + "value": "" + }, + { + "index": "3", + "name": "", + "value": "" + }, + { + "index": "2", + "name": "", + "value": "" + }, + { + "index": "1", + "name": "", + "value": "" + }, + { + "index": "0", + "name": "", + "value": "" + } + ], + "virtual": true, + "clock": false + }, + "position": { + "x": -104, + "y": 504 + } + }, + { + "id": "136cc2a3-009b-455d-aecb-b26cb259e486", + "type": "basic.input", + "data": { + "name": "led_eye_left_rgb_i", + "range": "[23:0]", + "pins": [ + { + "index": "23", + "name": "", + "value": "" + }, + { + "index": "22", + "name": "", + "value": "" + }, + { + "index": "21", + "name": "", + "value": "" + }, + { + "index": "20", + "name": "", + "value": "" + }, + { + "index": "19", + "name": "", + "value": "" + }, + { + "index": "18", + "name": "", + "value": "" + }, + { + "index": "17", + "name": "", + "value": "" + }, + { + "index": "16", + "name": "", + "value": "" + }, + { + "index": "15", + "name": "", + "value": "" + }, + { + "index": "14", + "name": "", + "value": "" + }, + { + "index": "13", + "name": "", + "value": "" + }, + { + "index": "12", + "name": "", + "value": "" + }, + { + "index": "11", + "name": "", + "value": "" + }, + { + "index": "10", + "name": "", + "value": "" + }, + { + "index": "9", + "name": "", + "value": "" + }, + { + "index": "8", + "name": "", + "value": "" + }, + { + "index": "7", + "name": "", + "value": "" + }, + { + "index": "6", + "name": "", + "value": "" + }, + { + "index": "5", + "name": "", + "value": "" + }, + { + "index": "4", + "name": "", + "value": "" + }, + { + "index": "3", + "name": "", + "value": "" + }, + { + "index": "2", + "name": "", + "value": "" + }, + { + "index": "1", + "name": "", + "value": "" + }, + { + "index": "0", + "name": "", + "value": "" + } + ], + "virtual": true, + "clock": false + }, + "position": { + "x": -104, + "y": 552 + } + }, + { + "id": "4e2de48f-16d4-4669-be41-bcdd717f6a58", + "type": "basic.output", + "data": { + "name": "data_spi", + "range": "[7:0]", + "pins": [ + { + "index": "7", + "name": "", + "value": "" + }, + { + "index": "6", + "name": "", + "value": "" + }, + { + "index": "5", + "name": "", + "value": "" + }, + { + "index": "4", + "name": "", + "value": "" + }, + { + "index": "3", + "name": "", + "value": "" + }, + { + "index": "2", + "name": "", + "value": "" + }, + { + "index": "1", + "name": "", + "value": "" + }, + { + "index": "0", + "name": "", + "value": "" + } + ], + "virtual": true + }, + "position": { + "x": 968, + "y": 592 + } + }, + { + "id": "5191ecd2-99f0-4b5b-9a5f-d10e8f8f7509", + "type": "basic.input", + "data": { + "name": "led_blink_rght_rgb_i", + "range": "[23:0]", + "pins": [ + { + "index": "23", + "name": "", + "value": "" + }, + { + "index": "22", + "name": "", + "value": "" + }, + { + "index": "21", + "name": "", + "value": "" + }, + { + "index": "20", + "name": "", + "value": "" + }, + { + "index": "19", + "name": "", + "value": "" + }, + { + "index": "18", + "name": "", + "value": "" + }, + { + "index": "17", + "name": "", + "value": "" + }, + { + "index": "16", + "name": "", + "value": "" + }, + { + "index": "15", + "name": "", + "value": "" + }, + { + "index": "14", + "name": "", + "value": "" + }, + { + "index": "13", + "name": "", + "value": "" + }, + { + "index": "12", + "name": "", + "value": "" + }, + { + "index": "11", + "name": "", + "value": "" + }, + { + "index": "10", + "name": "", + "value": "" + }, + { + "index": "9", + "name": "", + "value": "" + }, + { + "index": "8", + "name": "", + "value": "" + }, + { + "index": "7", + "name": "", + "value": "" + }, + { + "index": "6", + "name": "", + "value": "" + }, + { + "index": "5", + "name": "", + "value": "" + }, + { + "index": "4", + "name": "", + "value": "" + }, + { + "index": "3", + "name": "", + "value": "" + }, + { + "index": "2", + "name": "", + "value": "" + }, + { + "index": "1", + "name": "", + "value": "" + }, + { + "index": "0", + "name": "", + "value": "" + } + ], + "virtual": true, + "clock": false + }, + "position": { + "x": -104, + "y": 616 + } + }, + { + "id": "734d9762-f219-4091-8639-8f686819de29", + "type": "basic.code", + "data": { + "code": "// @include spi_ledctrl.v\r\n\r\n spi_ledctrl i_spi_ledctrl\r\n (\r\n .rst (rst),\r\n .clk (clk),\r\n .busy_spi (busy_spi),\r\n .motor_pwm_left_i (motor_pwm_left_i),\r\n .motor_pwm_rght_i (motor_pwm_rght_i),\r\n .led_eye_left_rgb_i (led_eye_left_rgb_i),\r\n .led_eye_rght_rgb_i (led_eye_rght_rgb_i),\r\n .led_blink_left_rgb_i (led_blink_left_rgb_i),\r\n .led_blink_rght_rgb_i (led_blink_rght_rgb_i),\r\n .spi_ss_n (spi_ss_n), // spi slave select\r\n .spi_send (spi_send),\r\n .ena_2clk (ena_2clk),\r\n .data_spi (data_spi)\r\n );\r\n", + "params": [], + "ports": { + "in": [ + { + "name": "rst" + }, + { + "name": "clk" + }, + { + "name": "busy_spi" + }, + { + "name": "motor_pwm_left_i", + "range": "[7:0]", + "size": 8 + }, + { + "name": "motor_pwm_rght_i", + "range": "[7:0]", + "size": 8 + }, + { + "name": "led_eye_left_rgb_i", + "range": "[23:0]", + "size": 24 + }, + { + "name": "led_eye_rght_rgb_i", + "range": "[23:0]", + "size": 24 + }, + { + "name": "led_blink_left_rgb_i", + "range": "[23:0]", + "size": 24 + }, + { + "name": "led_blink_rght_rgb_i", + "range": "[23:0]", + "size": 24 + } + ], + "out": [ + { + "name": "spi_ss_n" + }, + { + "name": "spi_send" + }, + { + "name": "ena_2clk" + }, + { + "name": "data_spi", + "range": "[7:0]", + "size": 8 + } + ] + } + }, + "position": { + "x": 280, + "y": 208 + }, + "size": { + "width": 552, + "height": 472 + } + } + ], + "wires": [ + { + "source": { + "block": "7be2ddb1-d6a1-4bd7-ae61-39bfb790c83a", + "port": "out" + }, + "target": { + "block": "734d9762-f219-4091-8639-8f686819de29", + "port": "rst" + } + }, + { + "source": { + "block": "27b9b159-fff3-4aa8-a549-d95bf7cffa35", + "port": "out" + }, + "target": { + "block": "734d9762-f219-4091-8639-8f686819de29", + "port": "busy_spi" + } + }, + { + "source": { + "block": "30efe8a5-78b5-4d54-9240-38fe50b23cf7", + "port": "out" + }, + "target": { + "block": "734d9762-f219-4091-8639-8f686819de29", + "port": "motor_pwm_left_i" + }, + "size": 8 + }, + { + "source": { + "block": "d9089370-ca82-4916-a658-332acf5559d7", + "port": "out" + }, + "target": { + "block": "734d9762-f219-4091-8639-8f686819de29", + "port": "motor_pwm_rght_i" + }, + "size": 8 + }, + { + "source": { + "block": "76d276fd-4d90-4f03-8e17-82b1cebc95b0", + "port": "out" + }, + "target": { + "block": "734d9762-f219-4091-8639-8f686819de29", + "port": "led_eye_left_rgb_i" + }, + "size": 24 + }, + { + "source": { + "block": "653def34-7abb-4924-8f15-8e326f02964e", + "port": "out" + }, + "target": { + "block": "734d9762-f219-4091-8639-8f686819de29", + "port": "led_eye_rght_rgb_i" + }, + "size": 24 + }, + { + "source": { + "block": "5191ecd2-99f0-4b5b-9a5f-d10e8f8f7509", + "port": "out" + }, + "target": { + "block": "734d9762-f219-4091-8639-8f686819de29", + "port": "led_blink_rght_rgb_i" + }, + "size": 24 + }, + { + "source": { + "block": "136cc2a3-009b-455d-aecb-b26cb259e486", + "port": "out" + }, + "target": { + "block": "734d9762-f219-4091-8639-8f686819de29", + "port": "led_blink_left_rgb_i" + }, + "size": 24 + }, + { + "source": { + "block": "734d9762-f219-4091-8639-8f686819de29", + "port": "spi_ss_n" + }, + "target": { + "block": "69dc2722-2a9d-4126-b109-7e31cfea16b6", + "port": "in" + } + }, + { + "source": { + "block": "734d9762-f219-4091-8639-8f686819de29", + "port": "spi_send" + }, + "target": { + "block": "252056ef-9e93-4572-9542-6c05ab5014f3", + "port": "in" + } + }, + { + "source": { + "block": "734d9762-f219-4091-8639-8f686819de29", + "port": "ena_2clk" + }, + "target": { + "block": "a4ff0e57-8710-43bd-84f6-c41eded90435", + "port": "in" + } + }, + { + "source": { + "block": "734d9762-f219-4091-8639-8f686819de29", + "port": "data_spi" + }, + "target": { + "block": "4e2de48f-16d4-4669-be41-bcdd717f6a58", + "port": "in" + }, + "size": 8 + }, + { + "source": { + "block": "a1e8c8a0-be11-4a4d-a19e-f8ee03fa17ae", + "port": "out" + }, + "target": { + "block": "734d9762-f219-4091-8639-8f686819de29", + "port": "clk" + } + } + ] + } + }, + "dependencies": {} +} \ No newline at end of file diff --git a/Blocks/General_Blocks/spi/alhambra_ii/spi_controller/Icestudio/spi_ctrl.v b/Blocks/General_Blocks/spi/alhambra_ii/spi_controller/Icestudio/spi_ctrl.v new file mode 100644 index 00000000..d4b80cef --- /dev/null +++ b/Blocks/General_Blocks/spi/alhambra_ii/spi_controller/Icestudio/spi_ctrl.v @@ -0,0 +1,435 @@ +////////////////////////////////////////////////////////////////////////////////// +// 12MHz clock +// Receives Motor PWM and leds commands for the GoPiGo3, and send them via SPI +// before sending them, check if there has been any change since the last sending + +module spi_ctrl +( + input rst, + input clk, + input busy_spi, + + input [7:0] motor_pwm_left_i, // left pwm motor ca2: -100 to 100 + input [7:0] motor_pwm_rght_i, // right pwm motor ca2: -100 to 100 + + // led eye left rgb color: 0 to 255 each channel R[23:16] G[15:8] B[7:0] + input [24-1:0] led_eye_left_rgb_i, + + // led eye right rgb color: 0 to 255 each channel R[23:16] G[15:8] B[7:0] + input [24-1:0] led_eye_rght_rgb_i, + + // led blink left rgb color: 0 to 255 each channel R[23:16] G[15:8] B[7:0] + input [24-1:0] led_blink_left_rgb_i, + + // led blink right rgb color: 0 to 255 each channel R[23:16] G[15:8] B[7:0] + input [24-1:0] led_blink_rght_rgb_i, + + output reg spi_ss_n, // spi slave select, active low + output reg spi_send, // command to send a new SPI byte + output ena_2clk, // ena spi, twice the frequency + output [7:0] data_spi +); + + // register of the inputs, to check if they have been modified since + // the last update to the SPI + reg [7:0] motor_pwm_left_rg; // 0: left pwm motor ca2: -100 to 100 + reg [7:0] motor_pwm_rght_rg; // 1: right pwm motor ca2: -100 to 100 + + // led eye left rgb color: 0 to 255 each channel R[23:16] G[15:8] B[7:0] + reg [24-1:0] led_eye_left_rgb_rg; // 2 + + // led eye right rgb color: 0 to 255 each channel R[23:16] G[15:8] B[7:0] + reg [24-1:0] led_eye_rght_rgb_rg; // 3 + + // led blink left rgb color: 0 to 255 each channel R[23:16] G[15:8] B[7:0] + reg [24-1:0] led_blink_left_rgb_rg; // 4 + + // led blink right rgb color: 0 to 255 each channel R[23:16] G[15:8] B[7:0] + reg [24-1:0] led_blink_rght_rgb_rg; // 5 + + // Register type + parameter + MOTOR_PWM_LEFT = 0, + MOTOR_PWM_RGHT = 1, + LED_EYE_LEFT = 2, + LED_EYE_RGHT = 3, + LED_BLINK_LEFT = 4, + LED_BLINK_RGHT = 5; + + parameter NUM_RGS = LED_BLINK_RGHT; + // counter to check all the register 0 to 5 + reg [3:0] cnt_chk_rgs; // range depends on NUM_RGS + // indicates if there has been any change in the registers having checked all + // of them + wire cnt_chk_rgs_ended; + // comparison between the input and the last sent command (registered) + reg [32-1:0] compare_port; // input port to compare + reg [32-1:0] compare_reg; // The largest argument so far has 4 bytes + reg any_rg_change; + + integer indx; // for the loop + + // 1: if the new command is the same as the last sent. Depends on the actual + // register that is being compared (cnt_chk_rgs) + wire rg_change; + + // counter for the SPI registers + reg [5:0] cnt_spi_byte; + reg incr_spi_byte; // increment the the SPI byte counter + + // FSM states to send SPI + parameter + CHK_NEW_SPI = 0, // check if there is any new SPI command to be sent + UPDATE_SPI_RGS = 1, // update the SPI registers, to send them + EN_SPI_ST = 2, // to have some time to active the SPI enable + // before sending any command + WAIT_SPI_ST = 3, // wait for the SPI to be ready (not busy) + SPI_SEND_ST = 4, // Send the SPI byte + SPI_SEND2_ST = 5, // wait for the SPI to be busy + EN_SPI2_ST = 6, // keeping the SPI enabled before dissabling it + FINISH_ST = 7; // Finish, and back to 0 + + reg [2:0] spi_state, spi_state_nxt; // present and next state + + // Maximum number of bytes to be sent in a command to SPI + // dont think there are more than 15 bytes to be sent via SPI + parameter N_SPI_BYTES = 16; + reg [8-1:0] spi_bytes [N_SPI_BYTES-1:0]; + parameter NB_SPI_BYTES = $clog2(N_SPI_BYTES); // number of bits + reg [NB_SPI_BYTES-1:0] last_spi_byte; // indicates the last SPI byte to be sent + + // slave select (chip enable) for the SPI of the slave (gopigo) + parameter C_SPI_SS_ON = 1'b0; // active low + parameter C_SPI_SS_OFF = 1'b1; + + reg [3:0] cnt_spi_clk; // count to 12 for the spi clock divider + //wire end_ena_2clk; + reg ena_spi_clk; // enable SPI clk + wire end_cnt_spi_clk; + + // counter that has a variable end of the count + reg [28:0] cnt_var; // to have time before sending the commands + // 25 bits: 33.5 millions -> 12MHz -> ~2.8 segs + wire cnt_var_ended; // indicates the end of the count + //reg [28:0] end_cnt_val; // indicates the value at the count finish + reg ena_cnt_var; // enable of the counter + + //parameter C_STARTUP_END = 2**25-1; // for synthesis + // 12MHz -> 83.3 ns x 33,554,432 -> + // 0,36Hz -> 2,8 s + //parameter C_STARTUP_END = 2**22-1; // for synthesis + // 12MHz -> 83.3 ns x 4,192,304 -> + // 2,86Hz -> 349ms + //parameter C_STARTUP_END = 1500-1; // for simulation + + //parameter C_EN_SPI_END = 2**20-1; // for synthesis + // 12MHz -> 83.3 ns x 10**6 -> + // 12Hz -> 83.3 ms + //parameter C_EN_SPI_END = 2**16-1; // for synthesis + // 12MHz -> 83.3 ns x 65000 -> + // 183Hz -> 5.5 ms + parameter C_EN_SPI_END = 500-1; // for simulation + + + always @(posedge rst, posedge clk) + begin + if (rst) begin + last_spi_byte <= 0; + spi_bytes[0] <= 8'h08; // SPI address, always first byte to be sent + for (indx=1; indx < N_SPI_BYTES; indx=indx+1) begin + spi_bytes[indx] <= 8'h00; + end + end + else begin + if (spi_state == CHK_NEW_SPI) begin + last_spi_byte <= 0; + spi_bytes[0] <= 8'h08; // SPI address, always first byte to be sent + // all registers to zero + for (indx=1; indx < N_SPI_BYTES; indx=indx+1) begin + spi_bytes[indx] <= 8'h00; + end + end + else if (spi_state == UPDATE_SPI_RGS) begin + case (cnt_chk_rgs) + MOTOR_PWM_LEFT: begin + spi_bytes[1] <= 8'h0A; // SPI Message type SET_MOTOR_PWM + spi_bytes[2] <= 8'h01; // MOTOR_LEFT + spi_bytes[3] <= motor_pwm_left_i; // PWM speed -100 to 100 + last_spi_byte <= 3; + end + MOTOR_PWM_RGHT: begin + spi_bytes[1] <= 8'h0A; // SPI Message type SET_MOTOR_PWM + spi_bytes[2] <= 8'h02; // MOTOR_RIGHT + spi_bytes[3] <= motor_pwm_rght_i; // PWM speed -100 to 100 + last_spi_byte <= 3; + end + LED_EYE_LEFT: begin + spi_bytes[1] <= 8'h06; // SPI Message type SET_LED + spi_bytes[2] <= 8'h02; // LED_EYE_LEFT + spi_bytes[3] <= led_eye_left_rgb_i[23:16]; // Red 0 to 255 + spi_bytes[4] <= led_eye_left_rgb_i[15:8]; // Green 0 to 255 + spi_bytes[5] <= led_eye_left_rgb_i[7:0]; // Blue 0 to 255 + last_spi_byte <= 5; + end + LED_EYE_RGHT: begin + spi_bytes[1] <= 8'h06; // SPI Message type SET_LED + spi_bytes[2] <= 8'h01; // LED_EYE_RIGHT + spi_bytes[3] <= led_eye_rght_rgb_i[23:16]; // Red 0 to 255 + spi_bytes[4] <= led_eye_rght_rgb_i[15:8]; // Green 0 to 255 + spi_bytes[5] <= led_eye_rght_rgb_i[7:0]; // Blue 0 to 255 + last_spi_byte <= 5; + end + LED_BLINK_LEFT: begin + spi_bytes[1] <= 8'h06; // SPI Message type SET_LED + spi_bytes[2] <= 8'h04; // LED_BLINK_LEFT + spi_bytes[3] <= led_blink_left_rgb_i[23:16]; // Red 0 to 255 + spi_bytes[4] <= led_blink_left_rgb_i[15:8]; // Green 0 to 255 + spi_bytes[5] <= led_blink_left_rgb_i[7:0]; // Blue 0 to 255 + last_spi_byte <= 5; + end + LED_BLINK_RGHT: begin + spi_bytes[1] <= 8'h06; // SPI Message type SET_LED + spi_bytes[2] <= 8'h08; // LED_BLINK_RIGHT + spi_bytes[3] <= led_blink_rght_rgb_i[23:16]; // Red 0 to 255 + spi_bytes[4] <= led_blink_rght_rgb_i[15:8]; // Green 0 to 255 + spi_bytes[5] <= led_blink_rght_rgb_i[7:0]; // Blue 0 to 255 + last_spi_byte <= 5; + end + endcase + end + end + end + + // register the new commands that have been sent (are just going to be sent) + always @(posedge rst, posedge clk) + begin + if (rst) begin + motor_pwm_left_rg <= 0; // 0 + motor_pwm_rght_rg <= 0; // 1 + led_eye_left_rgb_rg <= 0; // 2 + led_eye_rght_rgb_rg <= 0; // 3 + led_blink_left_rgb_rg <= 0; // 4 + led_blink_rght_rgb_rg <= 0; // 5 + end + else begin + if (spi_state == UPDATE_SPI_RGS) begin + case (cnt_chk_rgs) + MOTOR_PWM_LEFT: + motor_pwm_left_rg <= motor_pwm_left_i; + MOTOR_PWM_RGHT: + motor_pwm_rght_rg <= motor_pwm_rght_i; + LED_EYE_LEFT: + led_eye_left_rgb_rg <= led_eye_left_rgb_i; + LED_EYE_RGHT: + led_eye_rght_rgb_rg <= led_eye_rght_rgb_i; + LED_BLINK_LEFT: + led_blink_left_rgb_rg <= led_blink_left_rgb_i; + LED_BLINK_RGHT: + led_blink_rght_rgb_rg <= led_blink_rght_rgb_i; + endcase + end + end + end + + + + // counter to check all the registers + + always @(posedge rst, posedge clk) + begin + if (rst) + cnt_chk_rgs <= 0; + else begin + // only counts when checking if there are new SPI commands to be sent + if (spi_state == CHK_NEW_SPI) begin + if (rg_change==1'b0) begin // if no change, check the next one + if (cnt_chk_rgs_ended) + cnt_chk_rgs <= 0; + else + cnt_chk_rgs <= cnt_chk_rgs + 1'b1; + end + end + end + end + + assign cnt_chk_rgs_ended = (cnt_chk_rgs == NUM_RGS) ? 1'b1 : 1'b0; + + // depending on the register to be checked (given by cnt_chk_rgs) + // the register length is different. In order to use just one comparator, we'll + // select the registers and the inputs to be compared + always @(*) + begin + compare_port = 32'b0; + compare_reg = 32'b0; + case (cnt_chk_rgs) + MOTOR_PWM_LEFT: begin // one byte + compare_port[7:0] = motor_pwm_left_i; + compare_reg [7:0] = motor_pwm_left_rg; + end + MOTOR_PWM_RGHT: begin // one byte + compare_port[7:0] = motor_pwm_rght_i; + compare_reg [7:0] = motor_pwm_rght_rg; + end + LED_EYE_LEFT: begin // 3 bytes + compare_port[24-1:0] = led_eye_left_rgb_i; + compare_reg [24-1:0] = led_eye_left_rgb_rg; + end + LED_EYE_RGHT: begin // 3 bytes + compare_port[24-1:0] = led_eye_rght_rgb_i; + compare_reg [24-1:0] = led_eye_rght_rgb_rg; + end + LED_BLINK_LEFT: begin // 3 bytes + compare_port[24-1:0] = led_blink_left_rgb_i; + compare_reg [24-1:0] = led_blink_left_rgb_rg; + end + LED_BLINK_RGHT: begin // 3 bytes + compare_port[24-1:0] = led_blink_rght_rgb_i; + compare_reg [24-1:0] = led_blink_rght_rgb_rg; + end + endcase + end + + // -- compare if the actual command is the same as the last command sent + assign rg_change = (compare_port == compare_reg) ? 1'b0 : 1'b1; + + // -------------- timer (counter) to wait a configurable amount of time + + always @(posedge rst, posedge clk) + begin + if (rst) + cnt_var <= 0; + else begin + if (ena_cnt_var) begin + if (cnt_var_ended) + cnt_var <= 0; + else + cnt_var <= cnt_var + 1'b1; + end + else + cnt_var <= 0; + end + end + + assign cnt_var_ended = (cnt_var == C_EN_SPI_END) ? 1'b1 : 1'b0; + + + // -------------- SPI clock generation ----------------------- + // clk divider. Alhambra clock is 12 MHz, + // from the logic analyzer, SCK is 500 kHz, then ena_2clk has to be 1MHz + // count to 12 + always @(posedge rst, posedge clk) + begin + if (rst) + cnt_spi_clk <= 3'b0; + else begin + if ((end_cnt_spi_clk) || (ena_spi_clk == 1'b0)) + cnt_spi_clk <= 3'b0; + else + cnt_spi_clk <= cnt_spi_clk + 1'b1; + end + end + + // end of the count 0 to 11: 1 MHz signal + assign end_cnt_spi_clk = (cnt_spi_clk == 12-1) ? 1'b1 : 1'b0; + assign ena_2clk = end_cnt_spi_clk; + + + // ------------------- SPI register counter ----------------------- + always @ (posedge rst, posedge clk) + begin + if (rst) + cnt_spi_byte <= 0; + else begin + if (spi_state == CHK_NEW_SPI) + cnt_spi_byte <= 0; + else if (incr_spi_byte) + cnt_spi_byte <= cnt_spi_byte + 1'b1; + end + end + + // --------------- FINITE STATE MACHINE (FSM) ------------ + + // FSM sequential process + always @ (posedge rst, posedge clk) + begin + if (rst) + spi_state <= CHK_NEW_SPI; + else + spi_state <= spi_state_nxt; + end + + // FSM combinational process + always @ (*) + begin + spi_state_nxt = spi_state; // default value + ena_cnt_var = 1'b0; + spi_ss_n = C_SPI_SS_OFF; // disable the slave SPI + incr_spi_byte = 1'b0; + spi_send = 1'b0; + ena_spi_clk = 1'b0; // disable the generation of the SPI clock + case (spi_state) + CHK_NEW_SPI: begin // check if there is a new SPI command + if (rg_change) begin // There is a new SPI command to send + spi_state_nxt = UPDATE_SPI_RGS; // + end + end + UPDATE_SPI_RGS: begin // update the SPI registers + spi_state_nxt = EN_SPI_ST; // + end + EN_SPI_ST: begin // enable the SPI slave, and wait some time + ena_spi_clk = 1'b1; // enable the generation of the SPI clock + spi_ss_n = C_SPI_SS_ON; // enable the slave SPI + ena_cnt_var = 1'b1; + if (cnt_var_ended) begin + spi_state_nxt = SPI_SEND_ST; //SPI shouldnt be busy when just starting + ena_cnt_var = 1'b0; + end + end + WAIT_SPI_ST: begin + ena_spi_clk = 1'b1; // enable the generation of the SPI clock + spi_ss_n = C_SPI_SS_ON; // enable the slave SPI + if (!busy_spi) begin + spi_state_nxt = SPI_SEND_ST; + if (cnt_spi_byte == last_spi_byte) + spi_state_nxt = EN_SPI2_ST; // we are done + else // next byte + incr_spi_byte = 1'b1; // increment the byte except when 1 + end + end + SPI_SEND_ST: begin // send the new byte + ena_spi_clk = 1'b1; // enable the generation of the SPI clock + spi_ss_n = C_SPI_SS_ON; // enable the slave SPI + spi_send = 1'b1; + spi_state_nxt = SPI_SEND2_ST; + end + SPI_SEND2_ST: begin // to give time for the SPI to be busy + ena_spi_clk = 1'b1; // enable the generation of the SPI clock + spi_ss_n = C_SPI_SS_ON; // enable the slave SPI + spi_send = 1'b0; // the send command was activated in the transition + incr_spi_byte = 1'b0; + if (busy_spi) + spi_state_nxt = WAIT_SPI_ST; + end + EN_SPI2_ST: begin // finishing the transmission, enabling the SPI slave, + // before dissabling it + ena_spi_clk = 1'b1; // enable the generation of the SPI clock + spi_ss_n = C_SPI_SS_ON; // enable the slave SPI + ena_cnt_var = 1'b1; + if (cnt_var_ended) begin + spi_state_nxt = FINISH_ST; + ena_cnt_var = 1'b0; + end + end + FINISH_ST: begin // transmission ended, maybe not necessary and just jump + // to CHK_NEW_SPI + spi_state_nxt = CHK_NEW_SPI; + end + endcase + end + + // the SPI byte to send + assign data_spi = spi_bytes[cnt_spi_byte]; + + + +endmodule diff --git a/Projects/ComputerVision/xilinx_nexys4/ov7670_ObjectDetect/Nexys4DDR_Master.ucf b/Projects/ComputerVision/xilinx_nexys4/ov7670_ObjectDetect/Nexys4DDR_Master.ucf new file mode 100644 index 00000000..04bbe20b --- /dev/null +++ b/Projects/ComputerVision/xilinx_nexys4/ov7670_ObjectDetect/Nexys4DDR_Master.ucf @@ -0,0 +1,230 @@ +## This file is a general .ucf for the Nexys4 DDR Rev C board +## To use it in a project: +## - uncomment the lines corresponding to used pins +## - rename the used signals according to the project + +## Clock signal +NET "clk" LOC = "E3" | IOSTANDARD = "LVCMOS33"; #Bank = 35, Pin name = #IO_L12P_T1_MRCC_35, Sch name = clk100mhz +NET "clk" TNM_NET = sys_clk_pin; +TIMESPEC TS_sys_clk_pin = PERIOD sys_clk_pin 100 MHz HIGH 50%; + + +## Switches +#NET "sw0_test_cmd" LOC=J15 | IOSTANDARD=LVCMOS33; #IO_L24N_T3_RS0_15 +#NET "sw13_rgbmode<0>" LOC=L16 | IOSTANDARD=LVCMOS33; #IO_L3N_T0_DQS_EMCCLK_14 +#NET "sw13_rgbmode<1>" LOC=M13 | IOSTANDARD=LVCMOS33; #IO_L6N_T0_D08_VREF_14 +#NET "sw13_rgbmode<2>" LOC=R15 | IOSTANDARD=LVCMOS33; #IO_L13N_T2_MRCC_14 +#NET "sw4_test_osc" LOC=R17 | IOSTANDARD=LVCMOS33; #IO_L12N_T1_MRCC_14 +#NET "sw56_regs<0>" LOC=T18 | IOSTANDARD=LVCMOS33; #IO_L7N_T1_D10_14 +#NET "sw56_regs<1>" LOC=U18 | IOSTANDARD=LVCMOS33; #IO_L17N_T2_A13_D29_14 +#NET "sw<7>" LOC=R13 | IOSTANDARD=LVCMOS33; #IO_L5N_T0_D07_14 +#NET "sw<8>" LOC=T8 | IOSTANDARD=LVCMOS18; #IO_L24N_T3_34 +#NET "sw<9>" LOC=U8 | IOSTANDARD=LVCMOS18; #IO_25_34 +#NET "sw<10>" LOC=R16 | IOSTANDARD=LVCMOS33; #IO_L15P_T2_DQS_RDWR_B_14 +#NET "sw<11>" LOC=T13 | IOSTANDARD=LVCMOS33; #IO_L23P_T3_A03_D19_14 +#NET "sw<12>" LOC=H6 | IOSTANDARD=LVCMOS33; #IO_L24P_T3_35 +#NET "sw<13>" LOC=U12 | IOSTANDARD=LVCMOS33; #IO_L20P_T3_A08_D24_14 +#NET "sw<14>" LOC=U11 | IOSTANDARD=LVCMOS33; #IO_L19N_T3_A09_D25_VREF_14 +NET "rst" LOC=V10 | IOSTANDARD=LVCMOS33; #IO_L21P_T3_DQS_14 + + +## Buttons +#NET "cpu_resetn" LOC=C12 | IOSTANDARD=LVCMOS33; #IO_L3P_T0_DQS_AD1P_15 + +#NET "rst" LOC=N17 | IOSTANDARD=LVCMOS33; #IO_L9P_T1_DQS_14 +#NET "btnd" LOC=P18 | IOSTANDARD=LVCMOS33; #IO_L9N_T1_DQS_D13_14 +#NET "btnl_oscop" LOC=P17 | IOSTANDARD=LVCMOS33; #IO_L12P_T1_MRCC_14 +NET "sw2" LOC=M17 | IOSTANDARD=LVCMOS33; #IO_L10N_T1_D15_14 +#NET "btnu" LOC=M18 | IOSTANDARD=LVCMOS33; #IO_L4N_T0_D05_14 + + +## LEDs +NET "led<0>" LOC=H17 | IOSTANDARD=LVCMOS33; #IO_L18P_T2_A24_15 +NET "led<1>" LOC=K15 | IOSTANDARD=LVCMOS33; #IO_L24P_T3_RS1_15 +NET "led<2>" LOC=J13 | IOSTANDARD=LVCMOS33; #IO_L17N_T2_A25_15 +NET "led<3>" LOC=N14 | IOSTANDARD=LVCMOS33; #IO_L8P_T1_D11_14 +NET "led<4>" LOC=R18 | IOSTANDARD=LVCMOS33; #IO_L7P_T1_D09_14 +NET "led<5>" LOC=V17 | IOSTANDARD=LVCMOS33; #IO_L18N_T2_A11_D27_14 +NET "led<6>" LOC=U17 | IOSTANDARD=LVCMOS33; #IO_L17P_T2_A14_D30_14 +NET "led<7>" LOC=U16 | IOSTANDARD=LVCMOS33; #IO_L18P_T2_A12_D28_14 +NET "led<8>" LOC=V16 | IOSTANDARD=LVCMOS33; #IO_L16N_T2_A15_D31_14 +NET "led<9>" LOC=T15 | IOSTANDARD=LVCMOS33; #IO_L14N_T2_SRCC_14 +NET "led<10>" LOC=U14 | IOSTANDARD=LVCMOS33; #IO_L22P_T3_A05_D21_14 +NET "led<11>" LOC=T16 | IOSTANDARD=LVCMOS33; #IO_L15N_T2_DQS_DOUT_CSO_B_14 +NET "led<12>" LOC=V15 | IOSTANDARD=LVCMOS33; #IO_L16P_T2_CSI_B_14 +NET "led<13>" LOC=V14 | IOSTANDARD=LVCMOS33; #IO_L22N_T3_A04_D20_14 +NET "led<14>" LOC=V12 | IOSTANDARD=LVCMOS33; #IO_L20N_T3_A07_D23_14 +NET "led<15>" LOC=V11 | IOSTANDARD=LVCMOS33; #IO_L21N_T3_DQS_A06_D22_14 + + +##LEDs_RGB +#NET "led16_b" LOC=R12 | IOSTANDARD=LVCMOS33; #IO_L5P_T0_D06_14 +#NET "led16_g" LOC=M16 | IOSTANDARD=LVCMOS33; #IO_L10P_T1_D14_14 +#NET "led16_r" LOC=N15 | IOSTANDARD=LVCMOS33; #IO_L11P_T1_SRCC_14 +#NET "led17_b" LOC=G14 | IOSTANDARD=LVCMOS33; #IO_L15N_T2_DQS_ADV_B_15 +#NET "led17_g" LOC=R11 | IOSTANDARD=LVCMOS33; #IO_0_14 +#NET "led17_r" LOC=N16 | IOSTANDARD=LVCMOS33; #IO_L11N_T1_SRCC_14 + + +## 7 segment display +#NET "seg7<6>" LOC=T10 | IOSTANDARD=LVCMOS33; #IO_L24N_T3_A00_D16_14 +#NET "seg7<5>" LOC=R10 | IOSTANDARD=LVCMOS33; #IO_25_14 +#NET "seg7<4>" LOC=K16 | IOSTANDARD=LVCMOS33; #IO_25_15 +#NET "seg7<3>" LOC=K13 | IOSTANDARD=LVCMOS33; #IO_L17P_T2_A26_15 +#NET "seg7<2>" LOC=P15 | IOSTANDARD=LVCMOS33; #IO_L13P_T2_MRCC_14 +#NET "seg7<1>" LOC=T11 | IOSTANDARD=LVCMOS33; #IO_L19P_T3_A10_D26_14 +#NET "seg7<0>" LOC=L18 | IOSTANDARD=LVCMOS33; #IO_L4P_T0_D04_14 +#NET "dp" LOC=H15 | IOSTANDARD=LVCMOS33; #IO_L19N_T3_A21_VREF_15 + +#NET "anode7seg<0>" LOC=J17 | IOSTANDARD=LVCMOS33; #IO_L23P_T3_FOE_B_15 +#NET "anode7seg<1>" LOC=J18 | IOSTANDARD=LVCMOS33; #IO_L23N_T3_FWE_B_15 +#NET "anode7seg<2>" LOC=T9 | IOSTANDARD=LVCMOS33; #IO_L24P_T3_A01_D17_14 +#NET "anode7seg<3>" LOC=J14 | IOSTANDARD=LVCMOS33; #IO_L19P_T3_A22_15 +#NET "anode7seg<4>" LOC=P14 | IOSTANDARD=LVCMOS33; #IO_L8N_T1_D12_14 +#NET "anode7seg<5>" LOC=T14 | IOSTANDARD=LVCMOS33; #IO_L14P_T2_SRCC_14 +#NET "anode7seg<6>" LOC=K2 | IOSTANDARD=LVCMOS33; #IO_L23P_T3_35 +#NET "anode7seg<7>" LOC=U13 | IOSTANDARD=LVCMOS33; #IO_L23N_T3_A02_D18_14 + + +## Pmod Header JA +NET "ov7670_pwdn" LOC=C17 | IOSTANDARD=LVCMOS33; #IO_L20N_T3_A19_15 +NET "ov7670_d<0>" LOC=D18 | IOSTANDARD=LVCMOS33; #IO_L21N_T3_DQS_A18_15 +NET "ov7670_d<2>" LOC=E18 | IOSTANDARD=LVCMOS33; #IO_L21P_T3_DQS_15 +NET "ov7670_d<4>" LOC=G17 | IOSTANDARD=LVCMOS33; #IO_L18N_T2_A23_15 +NET "ov7670_rst_n" LOC=D17 | IOSTANDARD=LVCMOS33; #IO_L16N_T2_A27_15 +NET "ov7670_d<1>" LOC=E17 | IOSTANDARD=LVCMOS33; #IO_L16P_T2_A28_15 +NET "ov7670_d<3>" LOC=F18 | IOSTANDARD=LVCMOS33; #IO_L22N_T3_A16_15 +NET "ov7670_d<5>" LOC=G18 | IOSTANDARD=LVCMOS33; #IO_L22P_T3_A17_15 + +## Pmod Header JB +NET "ov7670_d<6>" LOC=D14 | IOSTANDARD=LVCMOS33; #IO_L1P_T0_AD0P_15 +NET "ov7670_xclk" LOC=F16 | IOSTANDARD=LVCMOS33; #IO_L14N_T2_SRCC_15 +NET "ov7670_href" LOC=G16 | IOSTANDARD=LVCMOS33; #IO_L13N_T2_MRCC_15 +NET "ov7670_siod" LOC=H14 | IOSTANDARD=LVCMOS33; #IO_L15P_T2_DQS_15 +NET "ov7670_d<7>" LOC=E16 | IOSTANDARD=LVCMOS33; #IO_L11N_T1_SRCC_15 +NET "ov7670_pclk" LOC=F13 | IOSTANDARD=LVCMOS33; #IO_L5P_T0_AD9P_15 +NET "ov7670_vsync" LOC=G13 | IOSTANDARD=LVCMOS33; #IO_0_15 +NET "ov7670_sioc" LOC=H16 | IOSTANDARD=LVCMOS33; #IO_L13P_T2_MRCC_15 + +## Pmod Header JC +#NET "jc<1>" LOC=K1 | IOSTANDARD=LVCMOS33; #IO_L23N_T3_35 +#NET "jc<2>" LOC=F6 | IOSTANDARD=LVCMOS33; #IO_L19N_T3_VREF_35 +#NET "jc<3>" LOC=J2 | IOSTANDARD=LVCMOS33; #IO_L22N_T3_35 +#NET "jc<4>" LOC=G6 | IOSTANDARD=LVCMOS33; #IO_L19P_T3_35 +#NET "jc<7>" LOC=E7 | IOSTANDARD=LVCMOS33; #IO_L6P_T0_35 +#NET "jc<8>" LOC=J3 | IOSTANDARD=LVCMOS33; #IO_L22P_T3_35 +#NET "jc<9>" LOC=J4 | IOSTANDARD=LVCMOS33; #IO_L21P_T3_DQS_35 +#NET "jc<10>" LOC=E6 | IOSTANDARD=LVCMOS33; #IO_L5P_T0_AD13P_35 + +## Pmod Header JD +#NET "jd<1>" LOC=H4 | IOSTANDARD=LVCMOS33; #IO_L21N_T3_DQS_35 +#NET "jd<2>" LOC=H1 | IOSTANDARD=LVCMOS33; #IO_L17P_T2_35 +#NET "jd<3>" LOC=G1 | IOSTANDARD=LVCMOS33; #IO_L17N_T2_35 +#NET "jd<4>" LOC=G3 | IOSTANDARD=LVCMOS33; #IO_L20N_T3_35 +#NET "jd<7>" LOC=H2 | IOSTANDARD=LVCMOS33; #IO_L15P_T2_DQS_35 +#NET "jd<8>" LOC=G4 | IOSTANDARD=LVCMOS33; #IO_L20P_T3_35 +#NET "jd<9>" LOC=G2 | IOSTANDARD=LVCMOS33; #IO_L15N_T2_DQS_35 +#NET "jd<10>" LOC=F3 | IOSTANDARD=LVCMOS33; #IO_L13N_T2_MRCC_35 + +##Pmod Header JXADC +#NET "xa_n<1>" LOC=A14 | IOSTANDARD=LVDS; #IO_L9N_T1_DQS_AD3N_15 +#NET "xa_p<1>" LOC=A13 | IOSTANDARD=LVDS; #IO_L9P_T1_DQS_AD3P_15 +#NET "xa_n<2>" LOC=A16 | IOSTANDARD=LVDS; #IO_L8N_T1_AD10N_15 +#NET "xa_p<2>" LOC=A15 | IOSTANDARD=LVDS; #IO_L8P_T1_AD10P_15 +#NET "xa_n<3>" LOC=B17 | IOSTANDARD=LVDS; #IO_L7N_T1_AD2N_15 +#NET "xa_p<3>" LOC=B16 | IOSTANDARD=LVDS; #IO_L7P_T1_AD2P_15 +#NET "xa_n<4>" LOC=A18 | IOSTANDARD=LVDS; #IO_L10N_T1_AD11N_15 +#NET "xa_p<4>" LOC=B18 | IOSTANDARD=LVDS; #IO_L10P_T1_AD11P_15 + + +##VGA Connector +NET "vga_red<0>" LOC=A3 | IOSTANDARD=LVCMOS33; #IO_L8N_T1_AD14N_35 +NET "vga_red<1>" LOC=B4 | IOSTANDARD=LVCMOS33; #IO_L7N_T1_AD6N_35 +NET "vga_red<2>" LOC=C5 | IOSTANDARD=LVCMOS33; #IO_L1N_T0_AD4N_35 +NET "vga_red<3>" LOC=A4 | IOSTANDARD=LVCMOS33; #IO_L8P_T1_AD14P_35 + +NET "vga_green<0>" LOC=C6 | IOSTANDARD=LVCMOS33; #IO_L1P_T0_AD4P_35 +NET "vga_green<1>" LOC=A5 | IOSTANDARD=LVCMOS33; #IO_L3N_T0_DQS_AD5N_35 +NET "vga_green<2>" LOC=B6 | IOSTANDARD=LVCMOS33; #IO_L2N_T0_AD12N_35 +NET "vga_green<3>" LOC=A6 | IOSTANDARD=LVCMOS33; #IO_L3P_T0_DQS_AD5P_35 + +NET "vga_blue<0>" LOC=B7 | IOSTANDARD=LVCMOS33; #IO_L2P_T0_AD12P_35 +NET "vga_blue<1>" LOC=C7 | IOSTANDARD=LVCMOS33; #IO_L4N_T0_35 +NET "vga_blue<2>" LOC=D7 | IOSTANDARD=LVCMOS33; #IO_L6N_T0_VREF_35 +NET "vga_blue<3>" LOC=D8 | IOSTANDARD=LVCMOS33; #IO_L4P_T0_35 + +NET "vga_hsync" LOC=B11 | IOSTANDARD=LVCMOS33; #IO_L4P_T0_15 +NET "vga_vsync" LOC=B12 | IOSTANDARD=LVCMOS33; #IO_L3N_T0_DQS_AD1N_15 + + +##Micro SD Connector +#NET "sd_sck" LOC=B1 | IOSTANDARD=LVCMOS33; #IO_L9P_T1_DQS_AD7P_35 +#NET "sd_reset" LOC=E2 | IOSTANDARD=LVCMOS33; #IO_L14P_T2_SRCC_35 +#NET "sd_cd" LOC=A1 | IOSTANDARD=LVCMOS33; #IO_L9N_T1_DQS_AD7N_35 +#NET "sd_cmd" LOC=C1 | IOSTANDARD=LVCMOS33; #IO_L16N_T2_35 +#NET "sd_dat<0>" LOC=C2 | IOSTANDARD=LVCMOS33; #IO_L16P_T2_35 +#NET "sd_dat<1>" LOC=E1 | IOSTANDARD=LVCMOS33; #IO_L18N_T2_35 +#NET "sd_dat<2>" LOC=F1 | IOSTANDARD=LVCMOS33; #IO_L18P_T2_35 +#NET "sd_dat<3>" LOC=D2 | IOSTANDARD=LVCMOS33; #IO_L14N_T2_SRCC_35 + + +##PWM Audio Amplifier +#NET "aud_pwm" LOC=A11 | IOSTANDARD=LVCMOS33; #IO_L4N_T0_15 +#NET "aud_sd" LOC=D12 | IOSTANDARD=LVCMOS33; #IO_L6P_T0_15 + + +##Accelerometer +#NET "acl_miso" LOC=E15 | IOSTANDARD=LVCMOS33; #IO_L11P_T1_SRCC_15 +#NET "acl_mosi" LOC=F14 | IOSTANDARD=LVCMOS33; #IO_L5N_T0_AD9N_15 +#NET "acl_sclk" LOC=F15 | IOSTANDARD=LVCMOS33; #IO_L14P_T2_SRCC_15 +#NET "acl_csn" LOC=D15 | IOSTANDARD=LVCMOS33; #IO_L12P_T1_MRCC_15 +#NET "acl_int<1>" LOC=B13 | IOSTANDARD=LVCMOS33; #IO_L2P_T0_AD8P_15 +#NET "acl_int<2>" LOC=C16 | IOSTANDARD=LVCMOS33; #IO_L20P_T3_A20_15 + + +##Temperature Sensor +#NET "tmp_ct" LOC=B14 | IOSTANDARD=LVCMOS33; #IO_L2N_T0_AD8N_15 +#NET "tmp_int" LOC=D13 | IOSTANDARD=LVCMOS33; #IO_L6N_T0_VREF_15 +#NET "tmp_scl" LOC=C14 | IOSTANDARD=LVCMOS33; #IO_L1N_T0_AD0N_15 +#NET "tmp_sda" LOC=C15 | IOSTANDARD=LVCMOS33; #IO_L12N_T1_MRCC_15 + + +##USB-RS232 Interface +#NET "uart_cts" LOC=D3 | IOSTANDARD=LVCMOS33; #IO_L12N_T1_MRCC_35 +#NET "uart_rts" LOC=E5 | IOSTANDARD=LVCMOS33; #IO_L5N_T0_AD13N_35 +#NET "uart_rxd_out" LOC=D4 | IOSTANDARD=LVCMOS33; #IO_L11N_T1_SRCC_35 +#NET "uart_txd_in" LOC=C4 | IOSTANDARD=LVCMOS33; #IO_L7P_T1_AD6P_35 + + +##Omnidirectional Microphone +#NET "m_clk" LOC=J5 | IOSTANDARD=LVCMOS33; #IO_25_35 +#NET "m_data" LOC=H5 | IOSTANDARD=LVCMOS33; #IO_L24N_T3_35 +#NET "m_lrsel" LOC=F5 | IOSTANDARD=LVCMOS33; #IO_0_35 + + +##USB HID (PS/2) +#NET "ps2_clk" LOC=F4 | IOSTANDARD=LVCMOS33; #IO_L13P_T2_MRCC_35 +#NET "ps2_data" LOC=B2 | IOSTANDARD=LVCMOS33; #IO_L10N_T1_AD15N_35 + + +##Quad SPI Flash +#NET "qspi_csn" LOC=L13 | IOSTANDARD=LVCMOS33; #IO_L6P_T0_FCS_B_14 +#NET "qspi_dq<0>" LOC=K17 | IOSTANDARD=LVCMOS33; #IO_L1P_T0_D00_MOSI_14 +#NET "qspi_dq<1>" LOC=K18 | IOSTANDARD=LVCMOS33; #IO_L1N_T0_D01_DIN_14 +#NET "qspi_dq<2>" LOC=L14 | IOSTANDARD=LVCMOS33; #IO_L2P_T0_D02_14 +#NET "qspi_dq<3>" LOC=M14 | IOSTANDARD=LVCMOS33; #IO_L2N_T0_D03_14 + + +##SMSC Ethernet PHY +#NET "eth_rxd<0>" LOC=C11 | IOSTANDARD=LVCMOS33; #IO_L13P_T2_MRCC_16 +#NET "eth_rxd<1>" LOC=D10 | IOSTANDARD=LVCMOS33; #IO_L19N_T3_VREF_16 +#NET "eth_txd<0>" LOC=A10 | IOSTANDARD=LVCMOS33; #IO_L14P_T2_SRCC_16 +#NET "eth_txd<1>" LOC=A8 | IOSTANDARD=LVCMOS33; #IO_L12N_T1_MRCC_16 +#NET "eth_crsdv" LOC=D9 | IOSTANDARD=LVCMOS33; #IO_L6N_T0_VREF_16 +#NET "eth_intn" LOC=B8 | IOSTANDARD=LVCMOS33; #IO_L12P_T1_MRCC_16 +#NET "eth_mdc" LOC=C9 | IOSTANDARD=LVCMOS33; #IO_L11P_T1_SRCC_16 +#NET "eth_mdio" LOC=A9 | IOSTANDARD=LVCMOS33; #IO_L14N_T2_SRCC_16 +#NET "eth_refclk" LOC=D5 | IOSTANDARD=LVCMOS33; #IO_L11P_T1_SRCC_35 +#NET "eth_rstn" LOC=B3 | IOSTANDARD=LVCMOS33; #IO_L10P_T1_AD15P_35 +#NET "eth_txen" LOC=B9 | IOSTANDARD=LVCMOS33; #IO_L11N_T1_SRCC_16 +#NET "eth_rxerr" LOC=C10 | IOSTANDARD=LVCMOS33; #IO_L13N_T2_MRCC_16 diff --git a/Projects/ComputerVision/xilinx_nexys4/ov7670_ObjectDetect/OV7670_Nexys_interface.png b/Projects/ComputerVision/xilinx_nexys4/ov7670_ObjectDetect/OV7670_Nexys_interface.png new file mode 100644 index 00000000..e0ec41a8 Binary files /dev/null and b/Projects/ComputerVision/xilinx_nexys4/ov7670_ObjectDetect/OV7670_Nexys_interface.png differ diff --git a/Projects/ComputerVision/xilinx_nexys4/ov7670_ObjectDetect/Top.v b/Projects/ComputerVision/xilinx_nexys4/ov7670_ObjectDetect/Top.v new file mode 100644 index 00000000..df2f57f3 --- /dev/null +++ b/Projects/ComputerVision/xilinx_nexys4/ov7670_ObjectDetect/Top.v @@ -0,0 +1,197 @@ +`timescale 1ns / 1ps +////////////////////////////////////////////////////////////////////////////////// +// Company: +// Engineer: +// +// Create Date: 00:16:58 06/10/2021 +// Design Name: +// Module Name: Top +// Project Name: +// Target Devices: +// Tool versions: +// Description: +// +// Dependencies: +// +// Revision: +// Revision 0.01 - File Created +// Additional Comments: +// +////////////////////////////////////////////////////////////////////////////////// +module Top( + input rst, //sw1 + input clk, + output ov7670_sioc, + output ov7670_siod, + output ov7670_rst_n, + output ov7670_pwdn, + + input ov7670_vsync, + input ov7670_href, + input ov7670_pclk, + output ov7670_xclk, + input [8-1:0] ov7670_d, + + + output [15:0] led, + input sw2, + + + output [3:0] vga_red, + output [3:0] vga_green, + output [3:0] vga_blue, + output vga_hsync, + output vga_vsync + ); + + + wire rgbmode, testmode; + wire [3-1:0] rgbfilter; + + wire swap_r_b; + assign swap_r_b = 1'b1; + + wire [13-1:0] capture_addr; + wire [12-1:0] capture_data; + wire capture_we; + + wire resend; + assign resend = 1'b0; + //wire ov7670_cfgdone; + wire [6-1:0] cnt_reg_test; + wire sdat_on; + wire sdat_out; + wire s_ov7670_xclk; + assign ov7670_xclk = s_ov7670_xclk; + + wire [12:0] s_addrb, s_addrb_post; + wire [11:0] s_doutb, s_doutb_post; + + wire s_proc_we; + wire [12:0] s_proc_img_addr; + wire [11:0] s_proc_img_pxl; + + wire visible, new_pxl; + wire s_vga_hsync, s_vga_vsync; + wire [9:0] col; + wire [9:0] row; + + +// Nombre archivo Nombre_proyecto + //archivo //señal o variable + mode_sel Mode_selecc + ( + .rst (rst), + .clk (clk), + .sig_in (sw2), + .rgbmode (rgbmode), + .testmode(testmode), + .rgbfilter (rgbfilter) + ); + + + ov7670_capture Captura_OV7670 + ( + .rst (rst), + .clk (clk), + .pclk (ov7670_pclk), + .href (ov7670_href), + .vsync (ov7670_vsync), + .rgbmode (rgbmode), + .swap_r_b(swap_r_b), + .data (ov7670_d), ///////////////////////////////// + .addr (capture_addr), + .dout (capture_data), + .we (capture_we) + ); + + + ov7670_top_ctrl TOP_Control_OV7670 + ( + .rst (rst), + .clk (clk), + .rgbmode (rgbmode), + .testmode(testmode), + .resend (resend), + //.done (ov7670_cfgdone), + .sclk (ov7670_sioc), + .sdat_on (sdat_on), + .sdat_out(sdat_out), + .ov7670_rst_n (ov7670_rst_n), + .ov7670_clk (s_ov7670_xclk), + .ov7670_pwdn (ov7670_pwdn) + ); + + + assign ov7670_siod = sdat_on ? sdat_out : 1'bz; + + framebuf_80x60_12b Buffer_preproc + ( + .clk (s_ov7670_xclk), + .wea (capture_we), + .addra (capture_addr), + .dina (capture_data), + .addrb (s_addrb), + .doutb (s_doutb) + ); + + + color_proc Filtro_color + ( + .rst (rst), + .clk (clk), + .rgbfilter (rgbfilter), + + .orig_addr (s_addrb), + .orig_pxl (s_doutb), + + .proc_we (s_proc_we), + .proc_addr (s_proc_img_addr), + .proc_pxl (s_proc_img_pxl), + .leds (led) + ); + + + framebuf_80x60_12b Buffer_postproc + ( + .clk (clk), + .wea (s_proc_we), + .addra (s_proc_img_addr), + .dina (s_proc_img_pxl), + .addrb (s_addrb_post), + .doutb (s_doutb_post) + ); + + + vga_sync sincro + ( + .rst (rst), + .clk (clk), + .visible (visible), + .new_pxl (new_pxl), + .hsync (vga_hsync), + .vsync (vga_vsync), + .col (col), + .row (row) + ); + + + vga_display pinta + ( + .rst (rst), + .clk (clk), + .visible (visible), + .new_pxl (new_pxl), + .rgbmode (rgbmode), + .testmode(testmode), + .rgbfilter(rgbfilter), + .col (col), + .row (row), + .frame_pixel (s_doutb_post), + .frame_addr (s_addrb_post), + .vga_red (vga_red), + .vga_green(vga_green), + .vga_blue(vga_blue) + ); + +endmodule diff --git a/Projects/ComputerVision/xilinx_nexys4/ov7670_ObjectDetect/color_proc.v b/Projects/ComputerVision/xilinx_nexys4/ov7670_ObjectDetect/color_proc.v new file mode 100644 index 00000000..f68bf67e --- /dev/null +++ b/Projects/ComputerVision/xilinx_nexys4/ov7670_ObjectDetect/color_proc.v @@ -0,0 +1,293 @@ +//------------------------------------------------------------------------------ +// Richard A. Nicklas +// +// color_proc.v +// Takes an image from a memory, light leds depending on red pixel position on frame +// +// + +module color_proc + # (parameter + // VGA + //c_img_cols = 640, // 10 bits + //c_img_rows = 480, // 9 bits + //c_img_pxls = c_img_cols * c_img_rows, + //c_nb_line_pxls = 10, // log2i(c_img_cols-1) + 1; + // c_nb_img_pxls = log2i(c_img_pxls-1) + 1 + //c_nb_img_pxls = 19, //640*480=307,200 -> 2^19=524,288 + // QQVGA + //c_img_cols = 160, // 8 bits + //c_img_rows = 120, // 7 bits + //c_img_pxls = c_img_cols * c_img_rows, + //c_nb_img_pxls = 15, //160*120=19.200 -> 2^15 + // QQVGA /2 + c_img_cols = 80, // 7 bits + c_img_rows = 60, // 6 bits + c_img_pxls = c_img_cols * c_img_rows, + c_nb_img_pxls = 13, //80*60=4800 -> 2^13 + + c_nb_buf_red = 4, // n bits for red in the buffer (memory) + c_nb_buf_green = 4, // n bits for green in the buffer (memory) + c_nb_buf_blue = 4, // n bits for blue in the buffer (memory) + // word width of the memory (buffer) + c_nb_buf = c_nb_buf_red + c_nb_buf_green + c_nb_buf_blue, + // position of the most significant bits of each color + c_msb_blue = c_nb_buf_blue-1, + c_msb_red = c_nb_buf-1, + c_msb_green = c_msb_blue + c_nb_buf_green + ) + ( + input rst, //reset, active high + input clk, //fpga clock + input [2:0] rgbfilter, // color filter to be applied + // Address and pixel of original image + input [c_nb_buf-1:0] orig_pxl, //pixel from original image + output [c_nb_img_pxls-1:0] orig_addr, //pixel mem address original img + // Address and pixel of processed image + output reg proc_we, //write enable, to write processed pxl + output reg [c_nb_buf-1:0] proc_pxl, // processed pixel to be written + output [c_nb_img_pxls-1:0] proc_addr, // address of processed pixel + + output [15:0] leds + ); + + + reg [c_nb_img_pxls-1:0] cnt_pxl; + reg [c_nb_img_pxls-1:0] cnt_pxl_proc; + reg [15:0] r_leds; + + wire end_pxl_cnt; + wire end_ln; + wire tmpw; + + parameter BLACK_PXL = {c_nb_img_pxls{1'b0}}; + +//array de 80 en el que cada indice tendre el numero de pixeles coloreados, +// indice con el valor mayor, luegom eso representa un octante. + + +//filtro mas led. + + + reg [5:0] histograma [79:0]; + + + integer col; + integer prev_high; + integer i; + integer j; + integer px_pos; + + integer tmp; + + // memory address count + always @ (posedge rst, posedge clk) + begin + if (rst) begin + cnt_pxl <= 0; + cnt_pxl_proc <= 0; + proc_we <= 1'b0; + end + else begin + proc_we <= 1'b1; + // data from memory received a clock cycle later + cnt_pxl_proc <= cnt_pxl; + if (end_pxl_cnt ) begin + cnt_pxl <= 0; + end + else + cnt_pxl <= cnt_pxl + 1'b1; + end + end + + assign end_pxl_cnt = (cnt_pxl == c_img_pxls-1) ? 1'b1 : 1'b0; + assign orig_addr = cnt_pxl; + assign proc_addr = cnt_pxl_proc; + + //wire para contar hasta 80 + assign end_ln = (px_pos == c_img_cols-1)? 1'b1 : 1'b0; + //aqui intento hacer la comprobacion para asignar un nuevo maximo a prev_high + + + +//Contador hasta 80 +always @ (posedge clk, posedge rst) + begin + if (rst) begin + px_pos <=0; + end + else if (end_ln) begin + px_pos <= 0; + end + else begin + px_pos <= px_pos +1; + end +end + +//según col pintamos LEDs +always @ (posedge clk, posedge rst) +begin + if (rst) begin + r_leds <= 16'd0; + end + else begin + if (col < 5) begin + r_leds <= 16'b1000_0000_0000_0000; + end + else if (col <10) begin + r_leds <= 16'b0100_0000_0000_0000; + end + else if (col <15) begin + r_leds <= 16'b0010_0000_0000_0000; + end + else if (col <20) begin + r_leds <= 16'b0001_0000_0000_0000; + end + else if (col <25) begin + r_leds <= 16'b0000_1000_0000_0000; + end + else if (col <30) begin + r_leds <= 16'b0000_0100_0000_0000; + end + else if (col <35) begin + r_leds <= 16'b0000_0010_0000_0000; + end + else if (col <40) begin + r_leds <= 16'b0000_0001_0000_0000; + end + else if (col <45) begin + r_leds <= 16'b0000_0000_1000_0000; + end + else if (col <50) begin + r_leds <= 16'b0000_0000_0100_0000; + end + else if (col <55) begin + r_leds <= 16'b0000_0000_0010_0000; + end + else if (col <60) begin + r_leds <= 16'b0000_0000_0001_0000; + end + else if (col <65) begin + r_leds <= 16'b0000_0000_0000_1000; + end + else if (col <70) begin + r_leds <= 16'b0000_0000_0000_0100; + end + else if (col <75) begin + r_leds <= 16'b0000_0000_0000_0010; + end + else begin + r_leds <= 16'b0000_0000_0000_0001; + end + + +/* + if (col < 39) begin + r_leds <= 8'b11100000; + end + else begin + r_leds <= 8'b00000111; + end */ + end +end + +//reg [5:0] histograma [79:0]; +//histograma almacena los pixeles rojos en cada columna, se resetea cada frame +always @ (posedge clk, posedge rst) +begin + if (rst) begin + for(i=0;i<=79;i=i+1) begin + histograma[i] <= 0; + end + end + else if (end_pxl_cnt) begin + for(i=0;i<=79;i=i+1) begin + histograma[i] <= 0; + end + end + else begin + if (orig_pxl[c_msb_red]) begin + histograma[px_pos] <= histograma[px_pos] + 1'b1; + // histograma[px_pos] <= 1; + end + end +end + + + assign tmpw = (prev_high < histograma[px_pos])? 1'b1 : 1'b0; + +//Si prev_high < el valor actual del histograma (tmpw) asignamos el nuevo maximo +// y guardamos la columna en col + + always @ (posedge clk, posedge rst) + begin + if (rst) begin + prev_high <=0; + col <=0; + end + else if(tmpw) begin + prev_high <= histograma[px_pos]; + col <= px_pos; + end + end + + + + /* + + */ + + assign leds = r_leds; + + always @ (orig_pxl, rgbfilter) // should include RGB mode + begin + // check on RED + case (rgbfilter) + 3'b000: // no filter, output same as input + proc_pxl <= orig_pxl; + 3'b100: begin // red filter + if (orig_pxl[c_msb_red]) + proc_pxl <= orig_pxl; + else + proc_pxl <= BLACK_PXL; + end + 3'b010: begin // green filter + if (orig_pxl[c_msb_green]) + proc_pxl <= orig_pxl; + else + proc_pxl <= BLACK_PXL; + end + 3'b001: begin // filter blue + if (orig_pxl[c_msb_blue]) + proc_pxl <= orig_pxl; + else + proc_pxl <= BLACK_PXL; + end + 3'b110: begin // filter red and green + if (orig_pxl[c_msb_red] & orig_pxl[c_msb_green]) + proc_pxl <= orig_pxl; + else + proc_pxl <= BLACK_PXL; + end + 3'b101: begin // filter red and blue + if (orig_pxl[c_msb_red] & orig_pxl[c_msb_blue]) + proc_pxl <= orig_pxl; + else + proc_pxl <= BLACK_PXL; + end + 3'b011: begin // filter green and blue + if (orig_pxl[c_msb_green] & orig_pxl[c_msb_blue]) + proc_pxl <= orig_pxl; + else + proc_pxl <= BLACK_PXL; + end + 3'b111: begin // red, green and blue filter + if (orig_pxl[c_msb_red] & orig_pxl[c_msb_green] & orig_pxl[c_msb_blue]) + proc_pxl <= orig_pxl; + else + proc_pxl <= BLACK_PXL; + end + endcase + end + +endmodule diff --git a/Projects/ComputerVision/xilinx_nexys4/ov7670_ObjectDetect/framebuf_80x60_12b.v b/Projects/ComputerVision/xilinx_nexys4/ov7670_ObjectDetect/framebuf_80x60_12b.v new file mode 100644 index 00000000..ffbf98f6 --- /dev/null +++ b/Projects/ComputerVision/xilinx_nexys4/ov7670_ObjectDetect/framebuf_80x60_12b.v @@ -0,0 +1,48 @@ +`timescale 1ns / 1ps +////////////////////////////////////////////////////////////////////////////////// +// Company: +// Engineer: +// +// Create Date: 01:24:50 06/10/2021 +// Design Name: +// Module Name: framebuf_80x60_12b +// Project Name: +// Target Devices: +// Tool versions: +// Description: +// +// Dependencies: +// +// Revision: +// Revision 0.01 - File Created +// Additional Comments: +// +////////////////////////////////////////////////////////////////////////////////// +module framebuf_80x60_12b( + input clk, + input wea, + input [12:0] addra, + input [11:0] dina, + input [12:0] addrb, + output reg [11:0] doutb + ); + + + parameter c_img_cols = 80; // # cols + parameter c_img_rows = 60; // # rows + parameter c_img_pxls = c_img_cols * c_img_rows; //4800=80x60 + parameter c_nb_img_pxls = 13; //80*60=4800 -> 2^13 + parameter c_nb_buf = 12; //4 bits for each color + + //reg doutb; //CAMBIO + reg [c_nb_buf-1:0] ram[c_img_pxls-1:0]; + + always @ (posedge clk) + begin + if (wea) + ram[addra] <= dina; + doutb <= ram[addrb]; + end + + +endmodule diff --git a/Projects/ComputerVision/xilinx_nexys4/ov7670_ObjectDetect/mode_sel.v b/Projects/ComputerVision/xilinx_nexys4/ov7670_ObjectDetect/mode_sel.v new file mode 100644 index 00000000..a8832d1e --- /dev/null +++ b/Projects/ComputerVision/xilinx_nexys4/ov7670_ObjectDetect/mode_sel.v @@ -0,0 +1,145 @@ +//------------------------------------------------------------------------------ +// Felipe Machado Sanchez +// Area de Tecnologia Electronica +// Universidad Rey Juan Carlos +// https://github.com/felipe-m +// +// mode selection +// + +module mode_sel + #(parameter + c_on = 1'b1 + ) + (input rst, + input clk, + input sig_in, + output reg rgbmode, + output reg testmode, + output [2:0] rgbfilter); + + reg [20-1:0] count_10ms; // ~1.05 million count -> 10 ms + reg [8-1:0] count_2sec; // count for 2.5 seconds aprox (256 x 10ms) + wire pulse_10ms; + wire pulse_1sec; + wire end1sec; + + reg [1:0] mode; + reg [2:0] rgb_filter; + + assign rgbfilter = rgb_filter; + + // count around 16 ms approx + always @(posedge rst, posedge clk) + begin + if (rst) begin + count_10ms <= 20'hF_FFFF; + end + else begin + if (sig_in) begin + if (count_10ms == 0) begin + count_10ms <= 20'hF_FFFF; + end + else + count_10ms <= count_10ms - 1'b1; + end + else + count_10ms <= 20'hF_FFFF; + end + end + + assign pulse_10ms = (count_10ms == 0) ? 1'b1 : 1'b0; + + // to see if it has been pulsed for more than a second + // the count is of 2 seconds to give time to release the button + always @(posedge rst, posedge clk) + begin + if (rst) begin + count_2sec <= 8'b0000_0000; + end + else begin + if (sig_in) begin + if (pulse_10ms) begin + if (count_2sec == 8'b1111_1111) + count_2sec <= 8'b0000_0000; + else + count_2sec <= count_2sec + 1'b1; + end + end + else + count_2sec <= 8'b0000_0000; + end + end + + assign end1sec = (count_2sec == 8'b0111_1111) ? 1'b1 : 1'b0; + assign pulse_1sec = ((end1sec==1'b1) && (pulse_10ms==1'b1)) ? 1'b1 : 1'b0; + + always @ (posedge rst, posedge clk) + begin + if (rst) begin + rgb_filter <= 3'b000; // no filter + end + else begin + if (pulse_10ms && count_2sec == 0) begin + case (rgb_filter) + 3'b000: // no filter, output same as input + rgb_filter <= 3'b100; // red filter + 3'b100: // red filter + rgb_filter <= 3'b010; // green filter + 3'b010: // green filter + rgb_filter <= 3'b001; // blue filter + 3'b001: // blue filter + rgb_filter <= 3'b110; // red and green filter + 3'b110: // red and green filter + rgb_filter <= 3'b101; // red and blue filter + 3'b101: // red and blue filter + rgb_filter <= 3'b011; // green and blue filter + 3'b011: // green and blue filter + rgb_filter <= 3'b111; // red, green and blue filter + 3'b111: // red, green and blue filter + rgb_filter <= 3'b000; // no filter + endcase + end + end + end + + always @ (posedge rst, posedge clk) + begin + if (rst) begin + mode <= 2'b0; + end + else begin + if (pulse_1sec) begin + if (mode == 2'b11) + mode <= 2'b0; + else + mode <= mode + 1'b1; + end + end + end + + + always @(*) + begin + case (mode) + 2'b00: begin // RGB Normal + rgbmode = 1'b1; + testmode = 1'b0; + end + 2'b01: begin // YUV Normal + rgbmode = 1'b0; + testmode = 1'b0; + end + 2'b10: begin // RGB Test + rgbmode = 1'b1; + testmode = 1'b1; + end + default: begin //2'b11: begin // YUV Test + rgbmode = 1'b0; + testmode = 1'b1; + end + endcase + end + +endmodule + diff --git a/Projects/ComputerVision/xilinx_nexys4/ov7670_ObjectDetect/ov7670_capture.v b/Projects/ComputerVision/xilinx_nexys4/ov7670_ObjectDetect/ov7670_capture.v new file mode 100644 index 00000000..9199f1bf --- /dev/null +++ b/Projects/ComputerVision/xilinx_nexys4/ov7670_ObjectDetect/ov7670_capture.v @@ -0,0 +1,240 @@ +//------------------------------------------------------------------------------ +// Felipe Machado Sanchez +// Area de Tecnologia Electronica +// Universidad Rey Juan Carlos +// https://github.com/felipe-m +// +// ov7670_capture.v +// +//----------------------------------------------------------------------------- + +module ov7670_capture + #(parameter + // VGA + //c_img_cols = 640, // 10 bits + //c_img_rows = 480, // 9 bits + //c_img_pxls = c_img_cols * c_img_rows, + //c_nb_line_pxls = 10, // log2i(c_img_cols-1) + 1; + // c_nb_img_pxls = log2i(c_img_pxls-1) + 1 + //c_nb_img_pxls = 19, //640*480=307,200 -> 2^19=524,288 + // QQVGA + //c_img_cols = 160, // 8 bits + //c_img_rows = 120, // 7 bits + //c_img_pxls = c_img_cols * c_img_rows, + //c_nb_line_pxls = 8, // log2i(c_img_cols-1) + 1; + //c_nb_img_pxls = 15, //160*120=19.200 -> 2^15 + // QQVGA/2 + c_img_cols = 7'd80, // 7 bits + c_img_rows = 60, // 6 bits + c_img_pxls = c_img_cols * c_img_rows, + c_nb_line_pxls = 7, // log2i(c_img_cols-1) + 1; + c_nb_img_pxls = 13, //80*60=4800 -> 2^13 + + + c_nb_buf_red = 4, // n bits for red in the buffer (memory) + c_nb_buf_green = 4, // n bits for green in the buffer (memory) + c_nb_buf_blue = 4, // n bits for blue in the buffer (memory) + // word width of the memory (buffer) + c_nb_buf = c_nb_buf_red + c_nb_buf_green + c_nb_buf_blue + ) + ( + input rst, // FPGA reset + input clk, // FPGA clock + // camera pclk (byte clock) (~40ns) + // 2 bytes is a pixel + input pclk, + input href, + input vsync, + input rgbmode, // RGB444 or YUV422 + input swap_r_b, // swaps red with blue + input [7:0] data, + output [c_nb_img_pxls-1:0] addr, + output [c_nb_buf-1:0] dout, + output we + ); + + reg pclk_rg1, pclk_rg2; // registered pclk + reg href_rg1, href_rg2; // registered href + reg vsync_rg1, vsync_rg2;// registered vsync + reg [7:0] data_rg1, data_rg2; //registered data + + reg pclk_rg3, href_rg3, vsync_rg3; //3rd + reg [7:0] data_rg3; // registered data 3rd + + // it seems that vsync has some spurious + wire vsync_3up; + + wire pclk_rise; + reg pclk_rise_post; + + reg cnt_byte; // count to 2: 2 bytes per pixel + reg [c_nb_img_pxls-1:0] cnt_pxl; + // number of pixels in the previous lines, not considering the actual line + reg [c_nb_img_pxls-1:0] cnt_pxl_base; + reg [c_nb_line_pxls-1:0] cnt_line_pxl; + + // there should be 4 clks in a pclk (byte), but just in case, make + // another bit to avoid overflow and go back in 0 before time + reg [4:0] cnt_clk; + reg [4:0] cnt_pclk_max; + + parameter c_cnt_05seg_end = 50_000_000; + + reg [7:0] gray; + reg [c_nb_buf_red-1:0] red; + reg [c_nb_buf_red-1:0] green; + reg [c_nb_buf_red-1:0] blue; + + // to test the number of + always @ (posedge rst, posedge clk) + begin + if (rst) begin + cnt_clk <= 0; + + end + else begin + if (href_rg2) begin + if (pclk_rise) begin + cnt_clk <= 0; + end + else + cnt_clk <= cnt_clk + 1'b1; + end + else + cnt_clk <= cnt_clk + 1'b1; + end + end + + // register 3 times all the camera inputs to synchronize + always @ (posedge rst, posedge clk) + begin + if (rst) begin + pclk_rg1 <= 1'b0; + pclk_rg2 <= 1'b0; + href_rg1 <= 1'b0; + href_rg2 <= 1'b0; + vsync_rg1 <= 1'b0; + vsync_rg2 <= 1'b0; + data_rg1 <= 0; + data_rg2 <= 0; + // 3rd to detect falling edge + pclk_rg3 <= 1'b0; + href_rg3 <= 1'b0; + vsync_rg3 <= 1'b0; + data_rg3 <= 0; + pclk_rise_post <= 1'b0; + end + else begin + pclk_rg1 <= pclk; + pclk_rg2 <= pclk_rg1; + href_rg1 <= href; + href_rg2 <= href_rg1; + vsync_rg1 <= vsync; + vsync_rg2 <= vsync_rg1; + data_rg1 <= data; + data_rg2 <= data_rg1; + // 3rd + pclk_rg3 <= pclk_rg2; + href_rg3 <= href_rg2; + vsync_rg3 <= vsync_rg2; + data_rg3 <= data_rg2; + pclk_rise_post <= pclk_rise; + end + end + + // since some times it is up up to 2 cycles, has to be '1' during + // the 3 following cycles + assign vsync_3up = vsync_rg3 && vsync_rg2 && vsync_rg1 && vsync; + + // FPGA clock is 10ns and pclk is 40ns + assign pclk_rise = (pclk_rg2 && (pclk_rg3 == 1'b0))? 1'b1 : 1'b0; + + // each pixel has 2 bytes, each byte in each pclk + // each pixel -> 2 pclk + always @ (posedge rst, posedge clk) + begin + if (rst) begin + cnt_pxl <= 0; + cnt_line_pxl <= 0; + cnt_pxl_base <= 0; + cnt_byte <= 1'b0; + end + else begin + //if vsync_rg3 = '1' then // there are some glitches + if (vsync_3up) begin // new screen + cnt_pxl <= 0; + cnt_pxl_base <= 0; + cnt_line_pxl <= 0; + cnt_byte <= 1'b0; + end + else if (href_rg3) begin // is zero at optical blank COM[6] + if (pclk_rise) begin + if (cnt_byte) begin + cnt_pxl <= cnt_pxl + 1'b1; + cnt_line_pxl <= cnt_line_pxl + 1'b1; + end + cnt_byte <= ~cnt_byte; + end + if (href_rg2 == 1'b0) begin // will be a falling edge + // it is not reliable to count all the pixels of a line, + // some lines have more other less + cnt_pxl <= cnt_pxl_base + c_img_cols; + cnt_pxl_base <= cnt_pxl_base + c_img_cols; + cnt_line_pxl <= 0; + end + end + else begin + cnt_byte <= 1'b0; + cnt_line_pxl <= 0; + end + end + end + + + always @ (posedge rst, posedge clk) + begin + if (rst) begin + red <= 0; + green <= 0; + blue <= 0; + gray <= 0; + end + else begin + if (href_rg3) begin // visible + //if (cnt_clk == 3'b001) begin // I think this is the safest + if (pclk_rise == 1'b1) begin + if (cnt_byte == 1'b0) begin + if (rgbmode) begin + if (swap_r_b == 1'b0) + red <= data_rg3[3:0]; + else + blue <= data_rg3[3:0]; + end + else // YUV (gray first byte) + gray <= data_rg3; + end + else begin + if (rgbmode) begin + green <= data_rg3[7:4]; + if (swap_r_b == 1'b0) + blue <= data_rg3[3:0]; + else + red <= data_rg3[3:0]; + end + //else + // do nothing, not getting U or V + end + end + end + end + end + + //dout <= (red & green & blue) when unsigned(sw13_rgbmode) < 3 else gray; + assign dout = (rgbmode) ? {red, green, blue} : {4'b000, gray}; + //dout <= std_logic_vector(cnt_pxl(7 downto 0)); + assign addr = cnt_pxl; + + assign we = (href_rg3 && cnt_byte && pclk_rise_post)? 1'b1 : 1'b0; + +endmodule + diff --git a/Projects/ComputerVision/xilinx_nexys4/ov7670_ObjectDetect/ov7670_ctrl_reg.v b/Projects/ComputerVision/xilinx_nexys4/ov7670_ObjectDetect/ov7670_ctrl_reg.v new file mode 100644 index 00000000..d89054f9 --- /dev/null +++ b/Projects/ComputerVision/xilinx_nexys4/ov7670_ObjectDetect/ov7670_ctrl_reg.v @@ -0,0 +1,1192 @@ +//------------------------------------------------------------------------------ +// Felipe Machado Sanchez +// Area de Tecnologia Electronica +// Universidad Rey Juan Carlos +// https://github.com/felipe-m +// +// ov7670_ctrl_reg.vhd +// Module in charge of telling the SCCB module what registers to write +// in the camera camera and to control the camera inputs: +// - ov7670_rst_n +// 0: camera reset +// 1: normal mode +// - pwdn: power down mode selection +// 0: normal mode +// 1: power down mode +// - xclk: system clock input +// freq : min: 10 MHz -- typ: 24 MHz -- Max: 48 MHz +// Period : max: 100 ns -- typ: 42 ns -- Max: 21 ns +// Register values taken from +// http://hamsterworks.co.nz/mediawiki/index.php/Zedboard_OV7670 +// http://hamsterworks.co.nz/mediawiki/index.php/OV7670_camera +//------------------------------------------------------------------------------ + +module ov7670_ctrl_reg + ( + input rst, //reset, active high + input clk, //fpga clock + input rgbmode, //if '1': in RGB mode + input testmode, //if '1': in test mode + input resend, //resend all the sequence + input sccb_ready, //SCCB ready to transmit + output start_tx, //start transmission + //output done, //all the registers written + output [6:0] id, //id of the slave + output [7:0] addr, //address to be written + output [7:0] data_wr, //data to write to slave + output ov7670_rst_n, //camera reset + output ov7670_clk, //camera system clock + output ov7670_pwdn //camera power down + ); + + + + // frequency divider for camera clk (divide by 4) + //signal cnt_cam_clk : unsigned (1 downto 0); + // frequency divider for camera clk (divide by 8) + reg [2:0] cnt_cam_clk; + + // 6 bits: less than 64 registers to be written, change if the number + // of registers to be written change + reg [5:0] cnt_reg; + + // auxiliary signal, connected to output port done + wire alltx_done; + + // auxiliary signal connected to output port ov7670_rst_n + reg cam_rst_n; + + // auxiliary signal, connected to start_tx + reg start_tx_aux; + + reg [25-1:0] cnt300ms; + wire end300ms; + reg ena_cnt300ms; + parameter c_end300ms = 30000000; + //parameter c_end300ms = 30; + + + + //id of the slave; 0x21. + // if adding the write bit, would be 0x42 for writing and 0x43 for reading + parameter c_id_write = 7'b0100_001; + wire [7:0] addr_aux; //address to be written + //wire [7:0] data_aux; //data to write to slave + // register from the register memory: address & data + reg [15:0] reg_i; + + parameter RSTCAM_ST = 0, // Reset camera during 300ms + WAIT_RSTCAM_ST = 1, // Wait 300ms for the camera to be ready + WAIT_ST = 2, // waiting to send, until not busy + WRITE_REG_ST = 3, // sending the initial sequence + DONE_ST = 4; // all the registers written + + // present state, next state + reg [2:0] pr_ctrl_st, nx_ctrl_st; // present state, next state + + // save the mode values to see if the have changed + reg rgbmode_old; + reg testmode_old; + wire mode_change; + + reg [15:0] reg_yuv422, reg_yuv422_test, reg_rgb444, reg_rgb444_test; + + + + // msb 8 bits are the address (15 downto 8) + // lsb 8 bits are the register value to be written + + always @ (cnt_reg) begin + // *IG means Implementation guide + case (cnt_reg) + 6'h00: + reg_rgb444_test <= 16'h1280; + // 12: COM7 Common Control 7 + // [7]=1: Reset all registers to default values + 6'h01: + reg_rgb444_test <= 16'h1280; + // 12: COM7 Common Control 7 + // [7]=1: Reset all registers to default values + 6'h02: + reg_rgb444_test <= 16'h1204; + // 12: COM7 Common Control 7 + // [1]=0: disable color bar (dont know what it is + // because a 0 also shows the test 8bar + // [2,0]="10": Output format RGB + 6'h03: + reg_rgb444_test <= 16'h0900; + // 09:COM2 Common Control 2. Default: 01 + // [7:5] : Reserved + // [4] : Soft sleep mode + // [3:2] : Reserved + // [1:0] : output drive capability, to increase IOL/OH drive + // 00: 1x + // 01: 2x + // 10: 3x + // 11: 4x + 6'h04: + reg_rgb444_test <= 16'h40F0; + // 40: COM15 Full 0-255 output, RGB 444 + // [7:6]="11": Full output range + // [5:4]="11": RGB 555 only if RGB444 is low + // so, this is to have RGB444 + // [3:0]=0: Reserved + 6'h05: + reg_rgb444_test <= 16'h8C02; + // 8C: RGB444 + // [7:2]=0: Reserved + // [1]=1: Enable RGB444 + // [0]=0: word format: xR GB + // =1: word format: RG Bx + 6'h06: + reg_rgb444_test <= 16'h1180; + // 11: CLKRC Internal Clock + // [7]=1: Reserved **IG says 0, but 1 seems stable + // [6]=0: Use pre-scale + // [5:0]: Interal clock pre-scalar + // F(internal clk) = F(input clk)/([5:0]+1) + // [5:0]= 0: No prescale (internal clk) + + 6'h07: + //reg_rgb444_test <= 16'h0F43; // 0F: COM6 Common Control 6 + reg_rgb444_test <= 16'h0F4B; + // 0F: COM6 Common Control 6 + // [7]=0: Disable HREF at optical blank + // [1]=1: Resets timming when format changes + // others reserved + // [3] = 1 (reserved) hamster + + 6'h08: + reg_rgb444_test <= 16'h1E37; + // MVFP Mirror/flip enable. Default 00 + // [7:6]= 00 : reserved + // [5]= 1 : Mirror image + // [4]= 1 : Flip image + // [3] : Reserved + // [2] : Black Sun Enable + // [1:0] : Reserved + + // color from hamster + 6'h09: + reg_rgb444_test <= 16'h1438; + // COM9 reserved: default 4A + // [6:4] Automatic Gain Ceiling - maximum AGC value + // 100 : 32x (default) + // 011 : 16x (default) + // [3:1] Reserved (default 101) + // 100 : Hamster + + //x"4F40", --x"4fb3", -- MTX1 - colour conversion matrix + //x"5034", --x"50b3", -- MTX2 - colour conversion matrix + //x"510C", --x"5100", -- MTX3 - colour conversion matrix + //x"5217", --x"523d", -- MTX4 - colour conversion matrix + //x"5329", --x"53a7", -- MTX5 - colour conversion matrix + //x"54E4", -- MTX6 - colour conversion matrix + //x"581E", --x"589e", -- MTXS - Matrix sign and auto contrast + + 6'h0A: + reg_rgb444_test <= 16'h4FB3; // MTX1 - colour conversion matrix + 6'h0B: + reg_rgb444_test <= 16'h50B3; // MTX2 - colour conversion matrix + 6'h0C: + reg_rgb444_test <= 16'h5100; // MTX3 - colour conversion matrix + 6'h0D: + reg_rgb444_test <= 16'h523D; // MTX4 - colour conversion matrix + 6'h0E: + reg_rgb444_test <= 16'h53A7; // MTX5 - colour conversion matrix + 6'h0F: + reg_rgb444_test <= 16'h54E4; // MTX6 - colour conversion matrix + 6'h10: + reg_rgb444_test <= 16'h589E; // MTXS - Matrix sign and auto contrast + + 6'h11: + reg_rgb444_test <= 16'h3DC0; // COM13: default 88 + // [7]=1 : Gamma enable (defaul) + // [6]=1 : UV Saturation Level - UV autoadjustment + // [5:1]: Reserved + // [0]: UV swap + + + // Trial and error + 6'h12: + reg_rgb444_test <= 16'hB084; // recommended TFG (reserved) + // hamster + 6'h13: + reg_rgb444_test <= 16'h0E61; // COM5 reserved: default 01 + 6'h14: + reg_rgb444_test <= 16'h1602; // reserved + 6'h15: + reg_rgb444_test <= 16'h2102; // ADCCTR0 (reserved): default 02 + 6'h16: + reg_rgb444_test <= 16'h2291; // ADCCTR1 (reserved): default 01 + 6'h17: + reg_rgb444_test <= 16'h2907; // RSVD (reserved): default XX + 6'h18: + reg_rgb444_test <= 16'h330B; // CHLF Array Current Control (reserved): + // default 08 + 6'h19: + reg_rgb444_test <= 16'h350B; // RSVD (reserved): default XX + 6'h1A: + reg_rgb444_test <= 16'h371D; // ADC (reserved): default 3F + 6'h1B: + reg_rgb444_test <= 16'h3871; // ACOM (reserved): default 01. + // ADC and Analog Common Mode Control + 6'h1C: + reg_rgb444_test <= 16'h392A; // OFON (reserved): default 00. + // ADC Offset Control + + 6'h1D: + reg_rgb444_test <= 16'h3C78; // COM12 (default 69) + // [7]= 0: No HREF when VSYNC is low + // [6:0]: Reserved + 6'h1E: + reg_rgb444_test <= 16'h4D40; // RSVD (reserved): default XX + 6'h1F: + reg_rgb444_test <= 16'h4E20; // RSVD (reserved): default XX + 6'h20: + reg_rgb444_test <= 16'h7410; // REG74 default 00 + // [4]=1 : Digital Gain control by REG74[1:0] + // [1:0]=00: Bypass + 6'h21: + reg_rgb444_test <= 16'h8D4F; // RSVD (reserved): default XX + 6'h22: + reg_rgb444_test <= 16'h8E00; // RSVD (reserved): default XX + 6'h23: + reg_rgb444_test <= 16'h8F00; // RSVD (reserved): default XX + 6'h24: + reg_rgb444_test <= 16'h9000; // RSVD (reserved): default XX + 6'h25: + reg_rgb444_test <= 16'h9100; // RSVD (reserved): default XX + 6'h26: + reg_rgb444_test <= 16'h9600; // RSVD (reserved): default XX + 6'h27: + reg_rgb444_test <= 16'h9A00; // RSVD (reserved): default XX + 6'h28: + reg_rgb444_test <= 16'hB10C; // ABLC1: default 00. + // Automatic Black Level Calibration + // [3]=1 : Reserved (hamster=1) + // [2]=1 : Enable ABLC + 6'h29: + reg_rgb444_test <= 16'hB20E; // RSVD (reserved): default XX + 6'h2A: + reg_rgb444_test <= 16'hB382; // THL_ST: ABLC Target: default 80 + // Lower limit of black leve +0x80 + 6'h2B: + reg_rgb444_test <= 16'hB80A; // RSVD (reserved): default XX + + + // --------- + + 6'h2C: + reg_rgb444_test <= 16'h1520; // 15: COM10 Common Control 10 + // [7]=0: Reserved + // [6]=0: Use HREF not HSYNC + // [5]=1: PCLK doesnt toggle during horizontl blank + // others default + 6'h2D: + reg_rgb444_test <= 16'h1711; // HSTART HREF start high 8-bit. + // The first pixels flicker + // 1700; // HSTART HREF start high 8-bit. + // For windowing. Dont want to do + 6'h2E: + reg_rgb444_test <= 16'h1800; // HSTOP HREF end high 8-bit. + // For windowing. Dont want to do + 6'h2F: + reg_rgb444_test <= 16'h1900; // VSTRT VREF start high 8-bit. + // For windowing. Dont want to do + 6'h30: + reg_rgb444_test <= 16'h1A00; // VSTOP VREF end high 8-bit. + // For windowing. Dont want to do + 6'h31: + reg_rgb444_test <= 16'h3200; // HREF Control + // [7:6] : HREF edge offset to data ouput + // [5:3] : HREF end LSB (high 8MSB at HSTOP) + // [2:0] : HREF start LSB (high 8MSB at HSTART + + + // -- QQVGA2 + 6'h32: + reg_rgb444_test <= 16'h0C04; // 0C: COM3 Common Control 3 + // [3]=1: Enable scale (for QQVGA/2) + // [2]=0: Disable DCW + // others default + 6'h33: + reg_rgb444_test <= 16'h3E1B; // 3E: COM14 Common Control 14 + // Scaling can be adjusted manually + // [7:5]: Reserved + // [4]=1: Scaling PCLK and DCW enabled + // Controlled by [2:0] and SCALING_PCLK_DIV + // [3]=1: Manual scaling enabled for predefined + // modes such QVGA + // [2:0] PCLK divided when COM14[4]=1 + // [2:0]=011: Divided by 8-> QQVGA/2: 80x60 + 6'h34: + reg_rgb444_test <= 16'h703A; // 70: SCALING_XSC + // [7]: test_pattern[0], works with test_pattern[1] + // 00: No test output + // 01: Shifting "1" + // 10: 8-bar color bar + // 11: Fade to gray color bar + // [7]= 0 -> 8-bar color bar (test_pattern[1]=1) + // [6:0]: default horizontal scale factor + 6'h35: + reg_rgb444_test <= 16'h71B5; // 71: SCALING_YSC + // [7]: test_pattern[1], works with test_pattern[0] + // 00: No test output + // 01: Shifting "1" + // 10: 8-bar color bar + // 11: Fade to gray color bar + // [7]= 1 -> 8-bar color bar (test_pattern[0]=0) + // [6:0]: default vertical scale factor + 6'h36: + reg_rgb444_test <= 16'h7233; // 72: SCALING_DCWCTR DCW Control + // [7]=0: Vertical average calc truncation(default) + // [6]=0: Vertical truncation downsampling(default) + // [5:4]: Vertical down sampling rate + // [5:4]=11: Vertical down sampling by 8->QQVGA/2 + // [3]=0: Horztal average calc truncation(default) + // [2]=0: Horztal truncation downsampling(default) + // [1:0]: Horztal down sampling rate + // [1:0]=11: Horztal down sampling by 8->QQVGA/2 + 6'h37: + reg_rgb444_test <= 16'h73F3; // 73: SCALING_PCLK_DIV + // [7:4]=F: Reserved, and manual says default is 0 + // but IG says F + // [3]=0: Enable clk divider for DSP scale control + // [2:0]=011: Divided by 8 -> QQVGA/2 + 6'h38: + reg_rgb444_test <= 16'hA202; // A2: SCALING_PCLK_DELAY Pixel Clock Delay + // [7]: Reserved + // [6:0]=02: Default scaling ouput delay + // end QQVGA + 6'h39: + reg_rgb444_test <= 16'hFFFF; // FINISH CONDITION, register FF doesnt exist + default: + reg_rgb444_test <= 16'hFFFF; // FINISH CONDITION + endcase + end + + + + + + + + always @ (cnt_reg) begin + // *IG means Implementation guide + case (cnt_reg) + 6'h00: + reg_rgb444 <= 16'h1280; + // 12: COM7 Common Control 7 + // [7]=1: Reset all registers to default values + 6'h01: + reg_rgb444 <= 16'h1280; + // 12: COM7 Common Control 7 + // [7]=1: Reset all registers to default values + 6'h02: + reg_rgb444 <= 16'h1204; + // 12: COM7 Common Control 7 + // [1]=0: disable color bar (dont know what it is + // because a 0 also shows the test 8bar + // [2,0]="10": Output format RGB + 6'h03: + reg_rgb444 <= 16'h0900; + // 09:COM2 Common Control 2. Default: 01 + // [7:5] : Reserved + // [4] : Soft sleep mode + // [3:2] : Reserved + // [1:0] : output drive capability, to increase IOL/OH drive + // 00: 1x : works best + // 01: 2x + // 10: 3x + // 11: 4x + 6'h04: + reg_rgb444 <= 16'h40F0; + // 40: COM15 Full 0-255 output, RGB 444 + // [7:6]="11": Full output range + // [5:4]="11": RGB 555 only if RGB444 is low + // so, this is to have RGB444 + // [3:0]=0: Reserved + 6'h05: + reg_rgb444 <= 16'h8C02; + // 8C: RGB444 + // [7:2]=0: Reserved + // [1]=1: Enable RGB444 + // [0]=0: word format: xR GB + // =1: word format: RG Bx + 6'h06: + reg_rgb444 <= 16'h1180; + // 11: CLKRC Internal Clock + // [7]=1: Reserved **IG says 0, but 1 seems stable + // [6]=0: Use pre-scale + // [5:0]: Interal clock pre-scalar + // F(internal clk) = F(input clk)/([5:0]+1) + // [5:0]= 0: No prescale (internal clk) + + 6'h07: + //reg_rgb444 <= 16'h0F43; // 0F: COM6 Common Control 6 + reg_rgb444 <= 16'h0F4B; + // 0F: COM6 Common Control 6 + // [7]=0: Disable HREF at optical blank + // [1]=1: Resets timming when format changes + // others reserved + // [3] = 1 (reserved) hamster + + 6'h08: + reg_rgb444 <= 16'h1E37; + // MVFP Mirror/flip enable. Default 00 + // [7:6]= 00 : reserved + // [5]= 1 : Mirror image + // [4]= 1 : Flip image + // [3] : Reserved + // [2] : Black Sun Enable + // [1:0] : Reserved + + // color from hamster + 6'h09: + reg_rgb444 <= 16'h1438; + // COM9 reserved: default 4A + // [6:4] Automatic Gain Ceiling - maximum AGC value + // 100 : 32x (default) + // 011 : 16x (default) + // [3:1] Reserved (default 101) + // 100 : Hamster + + //x"4F40", --x"4fb3", -- MTX1 - colour conversion matrix + //x"5034", --x"50b3", -- MTX2 - colour conversion matrix + //x"510C", --x"5100", -- MTX3 - colour conversion matrix + //x"5217", --x"523d", -- MTX4 - colour conversion matrix + //x"5329", --x"53a7", -- MTX5 - colour conversion matrix + //x"54E4", -- MTX6 - colour conversion matrix + //x"581E", --x"589e", -- MTXS - Matrix sign and auto contrast + + 6'h0A: + reg_rgb444 <= 16'h4FB3; // MTX1 - colour conversion matrix + 6'h0B: + reg_rgb444 <= 16'h50B3; // MTX2 - colour conversion matrix + 6'h0C: + reg_rgb444 <= 16'h5100; // MTX3 - colour conversion matrix + 6'h0D: + reg_rgb444 <= 16'h523D; // MTX4 - colour conversion matrix + 6'h0E: + reg_rgb444 <= 16'h53A7; // MTX5 - colour conversion matrix + 6'h0F: + reg_rgb444 <= 16'h54E4; // MTX6 - colour conversion matrix + 6'h10: + reg_rgb444 <= 16'h589E; // MTXS - Matrix sign and auto contrast + + 6'h11: + reg_rgb444 <= 16'h3DC0; // COM13: default 88 + // [7]=1 : Gamma enable (defaul) + // [6]=1 : UV Saturation Level - UV autoadjustment + // [5:1]: Reserved + // [0]: UV swap + + + // Trial and error + 6'h12: + reg_rgb444 <= 16'hB084; // recommended TFG (reserved) + // hamster + 6'h13: + reg_rgb444 <= 16'h0E61; // COM5 reserved: default 01 + 6'h14: + reg_rgb444 <= 16'h1602; // reserved + 6'h15: + reg_rgb444 <= 16'h2102; // ADCCTR0 (reserved): default 02 + 6'h16: + reg_rgb444 <= 16'h2291; // ADCCTR1 (reserved): default 01 + 6'h17: + reg_rgb444 <= 16'h2907; // RSVD (reserved): default XX + 6'h18: + reg_rgb444 <= 16'h330B; // CHLF Array Current Control (reserved): + // default 08 + 6'h19: + reg_rgb444 <= 16'h350B; // RSVD (reserved): default XX + 6'h1A: + reg_rgb444 <= 16'h371D; // ADC (reserved): default 3F + 6'h1B: + reg_rgb444 <= 16'h3871; // ACOM (reserved): default 01. + // ADC and Analog Common Mode Control + 6'h1C: + reg_rgb444 <= 16'h392A; // OFON (reserved): default 00. + // ADC Offset Control + + 6'h1D: + reg_rgb444 <= 16'h3C78; // COM12 (default 69) + // [7]= 0: No HREF when VSYNC is low + // [6:0]: Reserved + 6'h1E: + reg_rgb444 <= 16'h4D40; // RSVD (reserved): default XX + 6'h1F: + reg_rgb444 <= 16'h4E20; // RSVD (reserved): default XX + 6'h20: + reg_rgb444 <= 16'h7410; // REG74 default 00 + // [4]=1 : Digital Gain control by REG74[1:0] + // [1:0]=00: Bypass + 6'h21: + reg_rgb444 <= 16'h8D4F; // RSVD (reserved): default XX + 6'h22: + reg_rgb444 <= 16'h8E00; // RSVD (reserved): default XX + 6'h23: + reg_rgb444 <= 16'h8F00; // RSVD (reserved): default XX + 6'h24: + reg_rgb444 <= 16'h9000; // RSVD (reserved): default XX + 6'h25: + reg_rgb444 <= 16'h9100; // RSVD (reserved): default XX + 6'h26: + reg_rgb444 <= 16'h9600; // RSVD (reserved): default XX + 6'h27: + reg_rgb444 <= 16'h9A00; // RSVD (reserved): default XX + 6'h28: + reg_rgb444 <= 16'hB10C; // ABLC1: default 00. + // Automatic Black Level Calibration + // [3]=1 : Reserved (hamster=1) + // [2]=1 : Enable ABLC + 6'h29: + reg_rgb444 <= 16'hB20E; // RSVD (reserved): default XX + 6'h2A: + reg_rgb444 <= 16'hB382; // THL_ST: ABLC Target: default 80 + // Lower limit of black leve +0x80 + 6'h2B: + reg_rgb444 <= 16'hB80A; // RSVD (reserved): default XX + + + // --------- + + 6'h2C: + reg_rgb444 <= 16'h1520; // 15: COM10 Common Control 10 + // [7]=0: Reserved + // [6]=0: Use HREF not HSYNC + // [5]=1: PCLK doesnt toggle during horizontl blank + // others default + 6'h2D: + reg_rgb444 <= 16'h1711; // HSTART HREF start high 8-bit. + // The first pixels flicker + // 1700; // HSTART HREF start high 8-bit. + // For windowing. Dont want to do + 6'h2E: + reg_rgb444 <= 16'h1800; // HSTOP HREF end high 8-bit. + // For windowing. Dont want to do + 6'h2F: + reg_rgb444 <= 16'h1900; // VSTRT VREF start high 8-bit. + // For windowing. Dont want to do + 6'h30: + reg_rgb444 <= 16'h1A00; // VSTOP VREF end high 8-bit. + // For windowing. Dont want to do + 6'h31: + reg_rgb444 <= 16'h3200; // HREF Control + // [7:6] : HREF edge offset to data ouput + // [5:3] : HREF end LSB (high 8MSB at HSTOP) + // [2:0] : HREF start LSB (high 8MSB at HSTART + + + // -- QQVGA2 + 6'h32: + reg_rgb444 <= 16'h0C04; // 0C: COM3 Common Control 3 + // [3]=1: Enable scale (for QQVGA/2) + // [2]=0: Disable DCW + // others default + 6'h33: + reg_rgb444 <= 16'h3E1B; // 3E: COM14 Common Control 14 + // Scaling can be adjusted manually + // [7:5]: Reserved + // [4]=1: Scaling PCLK and DCW enabled + // Controlled by [2:0] and SCALING_PCLK_DIV + // [3]=1: Manual scaling enabled for predefined + // modes such QVGA + // [2:0] PCLK divided when COM14[4]=1 + // [2:0]=011: Divided by 8-> QQVGA/2: 80x60 + 6'h34: + reg_rgb444 <= 16'h703A; // 70: SCALING_XSC + // [7]: test_pattern[0], works with test_pattern[1] + // 00: No test output <- + // 01: Shifting "1" + // 10: 8-bar color bar + // 11: Fade to gray color bar + // [7]= 0 -> 8-bar color bar (test_pattern[1]=1) + // [6:0]: default horizontal scale factor + 6'h35: + reg_rgb444 <= 16'h7135; // 71: SCALING_YSC + // [7]: test_pattern[1], works with test_pattern[0] + // 00: No test output <- + // 01: Shifting "1" + // 10: 8-bar color bar + // 11: Fade to gray color bar + // [7]= 1 -> 8-bar color bar (test_pattern[0]=0) + // [6:0]: default vertical scale factor + 6'h36: + reg_rgb444 <= 16'h7233; // 72: SCALING_DCWCTR DCW Control + // [7]=0: Vertical average calc truncation(default) + // [6]=0: Vertical truncation downsampling(default) + // [5:4]: Vertical down sampling rate + // [5:4]=11: Vertical down sampling by 8->QQVGA/2 + // [3]=0: Horztal average calc truncation(default) + // [2]=0: Horztal truncation downsampling(default) + // [1:0]: Horztal down sampling rate + // [1:0]=11: Horztal down sampling by 8->QQVGA/2 + 6'h37: + reg_rgb444 <= 16'h73F3; // 73: SCALING_PCLK_DIV + // [7:4]=F: Reserved, and manual says default is 0 + // but IG says F + // [3]=0: Enable clk divider for DSP scale control + // [2:0]=011: Divided by 8 -> QQVGA/2 + 6'h38: + reg_rgb444 <= 16'hA202; // A2: SCALING_PCLK_DELAY Pixel Clock Delay + // [7]: Reserved + // [6:0]=02: Default scaling ouput delay + // end QQVGA + 6'h39: + reg_rgb444 <= 16'hFFFF; // FINISH CONDITION, register FF doesnt exist + default: + reg_rgb444 <= 16'hFFFF; // FINISH CONDITION + endcase + end + + + + + + always @ (cnt_reg) begin + // *IG means Implementation guide + case (cnt_reg) + 6'h00: + reg_yuv422_test <= 16'h1280; + // 12: COM7 Common Control 7 + // [7]=1: Reset all registers to default values + 6'h01: + reg_yuv422_test <= 16'h1280; + // 12: COM7 Common Control 7 + // [7]=1: Reset all registers to default values + 6'h02: + reg_yuv422_test <= 16'h1200; + // 12: COM7 Common Control 7 + // [2,0]= 00 : Output format YUV + 6'h03: + reg_yuv422_test <= 16'h0900; + // 09:COM2 Common Control 2. Default: 01 + // [7:5] : Reserved + // [4] : Soft sleep mode + // [3:2] : Reserved + // [1:0] : output drive capability, to increase IOL/OH drive + // 00: 1x : works best + // 01: 2x + // 10: 3x + // 11: 4x + 6'h04: + reg_yuv422_test <= 16'h40C0; + // 40: COM15 Full 0-255 output, RGB 444 + // [7:6] = 11 : Full output range + // [5:4] = x0 : Normal RGB output and YUV + // [5:4] = 11: RGB 55 only if RGB444 is low + // [3:0] = 0: Reserved + 6'h05: + reg_yuv422_test <= 16'h8C00; + // 8C: RGB444 + // [7:2]=0: Reserved + // [1]=1: Enable RGB444 + // [0]=0: word format: xR GB + 6'h06: + reg_yuv422_test <= 16'h1180; + // 11: CLKRC Internal Clock + // [7]=1: Reserved **IG says 0, but 1 seems stable + // [6]=0: Use pre-scale + // [5:0]: Interal clock pre-scalar + // F(internal clk) = F(input clk)/([5:0]+1) + // [5:0]= 0: No prescale (internal clk) + + 6'h07: + //reg_yuv422_test <= 16'h0F43; // 0F: COM6 Common Control 6 + reg_yuv422_test <= 16'h0F4B; //** check 0F4B + // 0F: COM6 Common Control 6 + // [7]=0: Disable HREF at optical blank + // [1]=1: Resets timming when format changes + // others reserved + // [3] = 1 (reserved) hamster + + // check + 6'h08: + reg_yuv422_test <= 16'h1E37; + // MVFP Mirror/flip enable. Default 00 + // [7:6]= 00 : reserved + // [5]= 1 : Mirror image + // [4]= 1 : Flip image + // [3] : Reserved + // [2] : Black Sun Enable + // [1:0] : Reserved + + // check + + // check + 6'h09: + reg_yuv422_test <= 16'h3DC0; // COM13: default 88 + // [7]=1 : Gamma enable (defaul) + // [6]=1 : UV Saturation Level - UV autoadjustment + // [5:1]: Reserved + // [0]: UV swap + + // --------- + + 6'h0A: + reg_yuv422_test <= 16'h1520; // 15: COM10 Common Control 10 + // [7]=0: Reserved + // [6]=0: Use HREF not HSYNC + // [5]=1: PCLK doesnt toggle during horizontl blank + // others default + 6'h0B: + reg_yuv422_test <= 16'h1711; // HSTART HREF start high 8-bit. + // The first pixels flicker + // 1700; // HSTART HREF start high 8-bit. + // For windowing. Dont want to do + 6'h0C: + reg_yuv422_test <= 16'h1800; // HSTOP HREF end high 8-bit. + // For windowing. Dont want to do + 6'h0D: + reg_yuv422_test <= 16'h1900; // VSTRT VREF start high 8-bit. + // For windowing. Dont want to do + 6'h0E: + reg_yuv422_test <= 16'h1A00; // VSTOP VREF end high 8-bit. + // For windowing. Dont want to do + 6'h0F: + reg_yuv422_test <= 16'h3200; // HREF Control + // [7:6] : HREF edge offset to data ouput + // [5:3] : HREF end LSB (high 8MSB at HSTOP) + // [2:0] : HREF start LSB (high 8MSB at HSTART + + 6'h10: + reg_yuv422_test <= 16'h3A04; // TLSB: Line buffer test option + // (default 0C) + // [7:6] : reserved + // [5] : negative image enable + // [5]=0 : Normal image + // [4]=0 : Use normal UV output + // [3] : Output sequence with COM13[1] + // TSLB[3], COM13[1]: + // 00: Y U Y V + // 01: Y U Y V + // 10: U Y V Y + // 11: V Y U Y + // [2:1] : Reserved + + + + + // -- QQVGA2 + 6'h11: + reg_yuv422_test <= 16'h0C04; // 0C: COM3 Common Control 3 + // [3]=1: Enable scale (for QQVGA/2) + // [2]=0: Disable DCW + // others default + 6'h12: + reg_yuv422_test <= 16'h3E1B; // 3E: COM14 Common Control 14 + // Scaling can be adjusted manually + // [7:5]: Reserved + // [4]=1: Scaling PCLK and DCW enabled + // Controlled by [2:0] and SCALING_PCLK_DIV + // [3]=1: Manual scaling enabled for predefined + // modes such QVGA + // [2:0] PCLK divided when COM14[4]=1 + // [2:0]=011: Divided by 8-> QQVGA/2: 80x60 + 6'h13: + reg_yuv422_test <= 16'h703A; // 70: SCALING_XSC + // [7]: test_pattern[0], works with test_pattern[1] + // 00: No test output + // 01: Shifting "1" + // 10: 8-bar color bar + // 11: Fade to gray color bar + // [7]= 0 -> 8-bar color bar (test_pattern[1]=1) + // [6:0]: default horizontal scale factor + 6'h14: + reg_yuv422_test <= 16'h71B5; // 71: SCALING_YSC + // [7]: test_pattern[1], works with test_pattern[0] + // 00: No test output + // 01: Shifting "1" + // 10: 8-bar color bar + // 11: Fade to gray color bar + // [7]= 1 -> 8-bar color bar (test_pattern[0]=0) + // [6:0]: default vertical scale factor + 6'h15: + reg_yuv422_test <= 16'h7233; // 72: SCALING_DCWCTR DCW Control + // [7]=0: Vertical average calc truncation(default) + // [6]=0: Vertical truncation downsampling(default) + // [5:4]: Vertical down sampling rate + // [5:4]=11: Vertical down sampling by 8->QQVGA/2 + // [3]=0: Horztal average calc truncation(default) + // [2]=0: Horztal truncation downsampling(default) + // [1:0]: Horztal down sampling rate + // [1:0]=11: Horztal down sampling by 8->QQVGA/2 + 6'h16: + reg_yuv422_test <= 16'h73F3; // 73: SCALING_PCLK_DIV + // [7:4]=F: Reserved, and manual says default is 0 + // but IG says F + // [3]=0: Enable clk divider for DSP scale control + // [2:0]=011: Divided by 8 -> QQVGA/2 + 6'h17: + reg_yuv422_test <= 16'hA202; // A2: SCALING_PCLK_DELAY Pixel Clock Delay + // [7]: Reserved + // [6:0]=02: Default scaling ouput delay + // end QQVGA + 6'h18: + reg_yuv422_test <= 16'hFFFF; // FINISH CONDITION, register FF doesnt exist + default: + reg_yuv422_test <= 16'hFFFF; // FINISH CONDITION + endcase + end + + + + + + always @ (cnt_reg) begin + // *IG means Implementation guide + case (cnt_reg) + 6'h00: + reg_yuv422 <= 16'h1280; + // 12: COM7 Common Control 7 + // [7]=1: Reset all registers to default values + 6'h01: + reg_yuv422 <= 16'h1280; + // 12: COM7 Common Control 7 + // [7]=1: Reset all registers to default values + 6'h02: + reg_yuv422 <= 16'h1200; + // 12: COM7 Common Control 7 + // [2,0]= 00 : Output format YUV + 6'h03: + reg_yuv422 <= 16'h0900; + // 09:COM2 Common Control 2. Default: 01 + // [7:5] : Reserved + // [4] : Soft sleep mode + // [3:2] : Reserved + // [1:0] : output drive capability, to increase IOL/OH drive + // 00: 1x + // 01: 2x + // 10: 3x + // 11: 4x + 6'h04: + reg_yuv422 <= 16'h40C0; + // 40: COM15 Full 0-255 output, RGB 444 + // [7:6] = 11 : Full output range + // [5:4] = x0 : Normal RGB output and YUV + // [5:4] = 11: RGB 55 only if RGB444 is low + // [3:0] = 0: Reserved + 6'h05: + reg_yuv422 <= 16'h8C00; + // 8C: RGB444 + // [7:2]=0: Reserved + // [1]=1: Enable RGB444 + // [0]=0: word format: xR GB + 6'h06: + reg_yuv422 <= 16'h1180; + // 11: CLKRC Internal Clock + // [7]=1: Reserved **IG says 0, but 1 seems stable + // [6]=0: Use pre-scale + // [5:0]: Interal clock pre-scalar + // F(internal clk) = F(input clk)/([5:0]+1) + // [5:0]= 0: No prescale (internal clk) + + 6'h07: + //reg_yuv422 <= 16'h0F43; // 0F: COM6 Common Control 6 + reg_yuv422 <= 16'h0F4B; //** check 0F4B + // 0F: COM6 Common Control 6 + // [7]=0: Disable HREF at optical blank + // [1]=1: Resets timming when format changes + // others reserved + // [3] = 1 (reserved) hamster + + 6'h08: + reg_yuv422 <= 16'h1E37; + // MVFP Mirror/flip enable. Default 00 + // [7:6]= 00 : reserved + // [5]= 1 : Mirror image + // [4]= 1 : Flip image + // [3] : Reserved + // [2] : Black Sun Enable + // [1:0] : Reserved + + 6'h09: + reg_yuv422 <= 16'h3DC0; // COM13: default 88 + // [7]=1 : Gamma enable (defaul) + // [6]=1 : UV Saturation Level - UV autoadjustment + // [5:1]: Reserved + // [0]: UV swap + + + // --------- + + 6'h0A: + reg_yuv422 <= 16'h1520; // 15: COM10 Common Control 10 + // [7]=0: Reserved + // [6]=0: Use HREF not HSYNC + // [5]=1: PCLK doesnt toggle during horizontl blank + // others default + 6'h0B: + reg_yuv422 <= 16'h1711; // HSTART HREF start high 8-bit. + // The first pixels flicker + // 1700; // HSTART HREF start high 8-bit. + // For windowing. Dont want to do + 6'h0C: + reg_yuv422 <= 16'h1800; // HSTOP HREF end high 8-bit. + // For windowing. Dont want to do + 6'h0D: + reg_yuv422 <= 16'h1900; // VSTRT VREF start high 8-bit. + // For windowing. Dont want to do + 6'h0E: + reg_yuv422 <= 16'h1A00; // VSTOP VREF end high 8-bit. + // For windowing. Dont want to do + 6'h0F: + reg_yuv422 <= 16'h3200; // HREF Control + // [7:6] : HREF edge offset to data ouput + // [5:3] : HREF end LSB (high 8MSB at HSTOP) + // [2:0] : HREF start LSB (high 8MSB at HSTART + + 6'h10: + reg_yuv422 <= 16'h3A04; // TLSB: Line buffer test option + // (default 0C) + // [7:6] : reserved + // [5] : negative image enable + // [5]=0 : Normal image + // [4]=0 : Use normal UV output + // [3] : Output sequence with COM13[1] + // TSLB[3], COM13[1]: + // 00: Y U Y V + // 01: Y U Y V + // 10: U Y V Y + // 11: V Y U Y + // [2:1] : Reserved + + + + + // -- QQVGA2 + 6'h11: + reg_yuv422 <= 16'h0C04; // 0C: COM3 Common Control 3 + // [3]=1: Enable scale (for QQVGA/2) + // [2]=0: Disable DCW + // others default + 6'h12: + reg_yuv422 <= 16'h3E1B; // 3E: COM14 Common Control 14 + // Scaling can be adjusted manually + // [7:5]: Reserved + // [4]=1: Scaling PCLK and DCW enabled + // Controlled by [2:0] and SCALING_PCLK_DIV + // [3]=1: Manual scaling enabled for predefined + // modes such QVGA + // [2:0] PCLK divided when COM14[4]=1 + // [2:0]=011: Divided by 8-> QQVGA/2: 80x60 + 6'h13: + reg_yuv422 <= 16'h703A; // 70: SCALING_XSC + // [7]: test_pattern[0], works with test_pattern[1] + // 00: No test output <- + // 01: Shifting "1" + // 10: 8-bar color bar + // 11: Fade to gray color bar + // [7]= 0 -> 8-bar color bar (test_pattern[1]=1) + // [6:0]: default horizontal scale factor + 6'h14: + reg_yuv422 <= 16'h7135; // 71: SCALING_YSC + // [7]: test_pattern[1], works with test_pattern[0] + // 00: No test output <- + // 01: Shifting "1" + // 10: 8-bar color bar + // 11: Fade to gray color bar + // [7]= 1 -> 8-bar color bar (test_pattern[0]=0) + // [6:0]: default vertical scale factor + 6'h15: + reg_yuv422 <= 16'h7233; // 72: SCALING_DCWCTR DCW Control + // [7]=0: Vertical average calc truncation(default) + // [6]=0: Vertical truncation downsampling(default) + // [5:4]: Vertical down sampling rate + // [5:4]=11: Vertical down sampling by 8->QQVGA/2 + // [3]=0: Horztal average calc truncation(default) + // [2]=0: Horztal truncation downsampling(default) + // [1:0]: Horztal down sampling rate + // [1:0]=11: Horztal down sampling by 8->QQVGA/2 + 6'h16: + reg_yuv422 <= 16'h73F3; // 73: SCALING_PCLK_DIV + // [7:4]=F: Reserved, and manual says default is 0 + // but IG says F + // [3]=0: Enable clk divider for DSP scale control + // [2:0]=011: Divided by 8 -> QQVGA/2 + 6'h17: + reg_yuv422 <= 16'hA202; // A2: SCALING_PCLK_DELAY Pixel Clock Delay + // [7]: Reserved + // [6:0]=02: Default scaling ouput delay + // end QQVGA + 6'h18: + reg_yuv422 <= 16'hFFFF; // FINISH CONDITION, register FF doesnt exist + default: + reg_yuv422 <= 16'hFFFF; // FINISH CONDITION + endcase + end + + + + // camera system clock: + // freq : min: 10 MHz -- typ: 24 MHz -- Max: 48 MHz + // Period : max: 100 ns -- typ: 42 ns -- Max: 21 ns + // duty cycle between 45% and 55% + // Since our clock is 10 ns (100 MHz), we have to divide frequency by: + // 4: 25 MHz - 40 ns + always @ (posedge rst, posedge clk) + begin + if (rst) + cnt_cam_clk <= 0; + else begin + if (cnt_cam_clk == 3'b011) + cnt_cam_clk <= 0; + else + cnt_cam_clk <= cnt_cam_clk + 1'b1; + end + end + + // when cnt_cam_clk = 0 | 1 => '0', when 2 | 3 => '1' + assign ov7670_clk = cnt_cam_clk[1]; + + // camera reset and power down + assign ov7670_pwdn = 1'b0; + + //------ controlling the registers to be sent ------------ + + assign id = c_id_write; // 0x21 + assign addr_aux = reg_i[15:8]; + assign addr = addr_aux; + assign data_wr = reg_i[7:0]; + + + assign ov7670_rst_n = cam_rst_n; + //assign done = alltx_done; + assign start_tx = start_tx_aux; + + // sequentially counts the registers to be sent to the SCCB + always @ (posedge rst, posedge clk) + begin + if (rst) + cnt_reg <= 0; + else begin + if (resend || mode_change) + cnt_reg <= 0; // start again sending the sequence + else if (~alltx_done) begin + if (start_tx_aux) + cnt_reg <= cnt_reg + 1'b1; + end + end + end + + // instead of comparing addr_aux = 16'hFF, to simplify, since there is no + // address in F ("1111"), it can be compared + assign alltx_done = (addr_aux[7:4] == 4'b1111) ? 1'b1 : 1'b0; + + always @ (posedge rst, posedge clk) + begin + if (rst) begin + rgbmode_old <= 1'b1; //starts in RGB mode + testmode_old <= 1'b0; //starts in normal mode + end + else begin + rgbmode_old <= rgbmode; + testmode_old <= testmode; + end + end + + // ^: xor (different). So if any are different + assign mode_change = (rgbmode ^ rgbmode_old) | (testmode ^ testmode_old); + + // without clk -> Distributed CLBS + // reg_i <= registers(to_integer(unsigned(cnt_reg)); + // process with clk -> BRAM + always @ (posedge rst, posedge clk) + begin + if (rst) + reg_i <= 16'h1280; // reset + else begin + if (rgbmode) begin + if (testmode) + reg_i <= reg_rgb444_test; + else + reg_i <= reg_rgb444; + end + else begin + if (testmode) + reg_i <= reg_yuv422_test; + else + reg_i <= reg_yuv422; + end + end + end + + + // FSM sequential process + always @ (posedge rst, posedge clk) + begin + if (rst) + pr_ctrl_st <= RSTCAM_ST; + else + pr_ctrl_st <= nx_ctrl_st; + end + + // FSM combinatorial process + always @ (pr_ctrl_st or alltx_done or sccb_ready or end300ms) + begin + // default values + nx_ctrl_st <= pr_ctrl_st; + start_tx_aux <= 1'b0; + cam_rst_n <= 1'b1; //camera reset inactive + ena_cnt300ms <= 1'b0; + case (pr_ctrl_st) + RSTCAM_ST: begin // Reset camera during 300ms + cam_rst_n <= 1'b0; //activate reset + ena_cnt300ms <= 1'b1; + if (end300ms) begin + nx_ctrl_st <= WAIT_RSTCAM_ST; + end + end + WAIT_RSTCAM_ST: begin // wait 300ms for the camera to be ready to receive + ena_cnt300ms <= 1'b1; + if (end300ms) begin + nx_ctrl_st <= WAIT_ST; + end + end + WAIT_ST: begin // waiting for the SCCB to be available + if (alltx_done) + nx_ctrl_st <= DONE_ST; + else if (sccb_ready) begin + nx_ctrl_st <= WRITE_REG_ST; + start_tx_aux <= 1'b1; + end + end + WRITE_REG_ST: begin // writting a new register (maybe not necessary) + ena_cnt300ms <= 1'b1; + if (end300ms) begin + nx_ctrl_st <= WAIT_ST; + end + end + DONE_ST: // writting a new register + if (~alltx_done) // in case of resend = '1' + nx_ctrl_st <= RSTCAM_ST; + endcase + end + + + // counting 300 ms at 100MHz clk: 30 million. 25 bits + always @ (posedge rst, posedge clk) + begin + if (rst) + cnt300ms <= 25'd0; + else begin + if (ena_cnt300ms) begin + if (end300ms) + cnt300ms <= 25'd0; + else + cnt300ms <= cnt300ms + 1'b1; + end + else + cnt300ms <= 25'd0; + end + end + + assign end300ms = (cnt300ms == c_end300ms) ? 1'b1 : 1'b0; + + + + +endmodule diff --git a/Projects/ComputerVision/xilinx_nexys4/ov7670_ObjectDetect/ov7670_top_ctrl.v b/Projects/ComputerVision/xilinx_nexys4/ov7670_ObjectDetect/ov7670_top_ctrl.v new file mode 100644 index 00000000..6a8e50ea --- /dev/null +++ b/Projects/ComputerVision/xilinx_nexys4/ov7670_ObjectDetect/ov7670_top_ctrl.v @@ -0,0 +1,70 @@ +//------------------------------------------------------------------------------ +// Felipe Machado Sanchez +// Area de Tecnologia Electronica +// Universidad Rey Juan Carlos +// https://github.com/felipe-m +// +// ov7670_top_ctrl.v +// structural model, that controls the OV7670 camera, send the registers +// and controls the camera +//------------------------------------------------------------------------------ + +module ov7670_top_ctrl + (input rst, //reset, active high + input clk, //FPGA clock + input resend, //resend the sequence + input rgbmode, //if '1': in RGB, else YUV + input testmode, //if '1': in test mode + //output done, //all transmission done + output sclk, //sccb clock + output sdat_on, //transmitting serial ('1') + //output sdat_in, //sccb serial data in + output sdat_out, //sccb serial data ou + output ov7670_rst_n, //camera reset + output ov7670_clk, //camera system clock + output ov7670_pwdn //camera power down + ); + + + wire start_tx; + wire sccb_ready; + wire [6:0] id; + wire [7:0] addr; + wire [7:0] data_wr; + + sccb_master i_sccb + ( + .rst (rst), + .clk (clk), + .start_tx (start_tx), + .id (id), + .addr (addr), + .data_wr (data_wr), + .ready (sccb_ready), + //.finish_tx + .sclk (sclk), + .sdat_on (sdat_on), + //sdat_in + .sdat_out (sdat_out) + ); + + + ov7670_ctrl_reg i_regs + ( + .rst (rst), + .clk (clk), + .rgbmode (rgbmode), + .testmode (testmode), + .resend (resend), + .sccb_ready (sccb_ready), + .start_tx (start_tx), + //.done (done), + .id (id), + .addr (addr), + .data_wr (data_wr), + .ov7670_rst_n (ov7670_rst_n), + .ov7670_clk (ov7670_clk), + .ov7670_pwdn (ov7670_pwdn) + ); + +endmodule diff --git a/Projects/ComputerVision/xilinx_nexys4/ov7670_ObjectDetect/sccb_master.v b/Projects/ComputerVision/xilinx_nexys4/ov7670_ObjectDetect/sccb_master.v new file mode 100644 index 00000000..1f5ebaa6 --- /dev/null +++ b/Projects/ComputerVision/xilinx_nexys4/ov7670_ObjectDetect/sccb_master.v @@ -0,0 +1,343 @@ +//------------------------------------------------------------------------------ +// Felipe Machado Sanchez +// Area de Tecnologia Electronica +// Universidad Rey Juan Carlos +// https://github.com/felipe-m +// +// sccb_master.v +// Module in charge of the SCCB communication with the OmniVision OV7670 +// camera. +// SCCB (Serial Camera Control Bus) is like the I2C +// This module is the master. +// For this first version, it will only write to the camera, therefore +// it will be a 3-phase write transmission cycle +// As explained in the Register Set section of the datasheet, the camera +// slave address is x"42" (0x42, hexadecimal) for writting and and x"43" for +// reading +// +// Instead of generics, constants are defined in packages +// +// 0 1 2 3 +// :________: ___: ___: +// SCL : :\___/ :\___/ : +// : : : : +// :__ : _____:__ _____: +// SDA : \_____:__/__d7_:__X__d6_: +// :0 1 2 3 :0 1 2 3 :0 1 2 3 +// : : +// :.Tsccb..: + +// init dont Another phase +// sequence 0 1 2 3 care OR end bit +// :______ : ___ : ___ : : ___ : ___ : ______ +// SCL : \_:__/ \_:__/ \_: :__/ \_:__/ \_:_/ +// : : : : : : : +// :__ : _______: _______: : _______: _______: ____ +// SDA : \_____:/__d7___:X__d6___: :X__d0___:X___Z___:___/ +// :0 1 2 3 :0 1 2 3 :0 1 2 3 +// : : +// :.Tsccb..: DNTC_ST:END_SEQ_ST +// INIT_SEQ_ST +// +// The period Tsccb is divided in 4 parts. +// SCL changes at the end of 1st and 3rd quarters +// SDA changes at the end of the peridod (end of last (4th) quarter) +// When transmiting bits, SDA must not change when SCL is high +// Max frequency of the sccb clock 400 KHz: Period 2.5 us +// Half of the time will be high, the other half low: 1.25 us +// However, the minimum clok low period for the sccb_clk is 1.3 us +// making low and high the same time, would be 2.6 us (~384,6 KHz) +// We will make a divider of the 1/4 the period, to be able to change +// the signals at the quarter. That would be 650 ns. + +// + + +module sccb_master + #(parameter + c_off = 1'b0, // push button off + c_on = ~c_off, // push button on + c_clk_period = 10, // fpga clk peridod in ns + // quarter of a period in ns + c_sclk_period_div4 = 650, // see explanation above + // frequency divider counter end value. Divided by 4 to have it divided + // in 4 slots + // we use div_ceil, to avoid having a smaller end count, + // which would mean higher frequency + c_sclk_div4_endcnt = 65, // div_ceil(c_sclk_period_div4,c_clk_period); + // number of bits necessary to represent c_sclk_endcont in binary + c_nb_cnt_sclk_div4 = 7 // log2i(c_sclk_div4_endcnt-1) + 1; + ) + ( + input rst, //reset, active high + input clk, //fpga clock + input start_tx, //start transmission + input [6:0] id, //id of the slave + input [7:0] addr, //address to be written + input [7:0] data_wr, //data to write to slave + output ready, //ready to send + //output reg finish_tx, //transmission finished(pulse + output reg sclk, //sccb clock + output reg sdat_on, //transmitting serial ('1') + //input sdat_in, //sccb serial data in + output reg sdat_out //sccb serial data out + ); + + + // saving in registers the slave ID, address or the register + // and data to be written. 8x3 = 24 bits + //signal id_rg : std_logic_vector(7 downto 0); //id of the slave + //signal addr_rg : std_logic_vector(7 downto 0); //address to be written + //signal data_rg : std_logic_vector(7 downto 0); //data to write to slave + reg [24-1:0] send_rg; //id, addr and data + + + // frequency divider, but 4 time faster than the sccb period + reg [c_nb_cnt_sclk_div4-1:0] cnt_sclk_div4; + // indicates that the count reached the end: end of a quarter + wire sclk_div4_end; + + // count of the four quarters of the scc clock + reg [1:0] cnt_4sclk; + wire sclk_end; // end of a sccb_clk cycle + + // count the 3 phases of the sending: + // 0: slave ID + // 1: address of the register to be written + // 2: data to be written + reg [1:0] cnt_phases; + reg new_phase; // end of a phase, starting a new one + wire phases_end; // end of the 3 phases + + reg ready_aux; // not busy, ready to receive + + // sccb_states: + parameter IDLE_ST = 0, // waiting to send, not busy + INIT_SEQ_ST = 1, // sending the initial sequence + SEND_BYTE_ST = 2, // sending the byte of any of the 3 phases + DNTC_ST = 3, // dont care bit, in i2c would be ack + END_SEQ_ST = 4; // sending the end sequence + + reg [2:0] pr_sccb_st; // present state + reg [2:0] nx_sccb_st; // next state + + // enable the counter of bits to send data and shifting the registers + // in any of the 3 phases: ID_ADDR_ST, REG_ADDR_ST, SEND_BYTE_ST + reg send_data; + // counter + reg [2:0] cnt_8bits; // 3 bits to count 0 to 7 + // end of the 8 bit count + wire cnt_8bits_end; + + // indication to save id, address and data to write + reg save_indata; + //clear registers where the data to send is saved + reg clr_datarg; + + assign ready = (rst == c_off) ? ready_aux : 1'b0; // if reset, not ready + + always @ (posedge rst, posedge clk) + begin + if (rst) + // the line is inactive at '1' + send_rg <= {24{1'b1}}; // '1' in all 24 bits + else begin + if (clr_datarg) + send_rg <= {24{1'b1}}; // all to '1' + else if (save_indata) + //'0' indicates we are writting in the slave. Reading not implemented + // id has 7 bits + send_rg <= {id, 1'b0, addr, data_wr}; + else if (send_data) begin + if (sclk_end) + // rotate left, fillings with '1' + send_rg <= {send_rg[23-1:0], 1'b1}; + end + end + end + + // counting a quarter of the sccb clk period + always @ (posedge rst, posedge clk) + begin + if (rst) + cnt_sclk_div4 <= 0; + else begin + if (ready_aux) + cnt_sclk_div4 <= 0; + else begin + if (sclk_div4_end) + cnt_sclk_div4 <= 0; + else + cnt_sclk_div4 <= cnt_sclk_div4 + 1'b1; + end + end + end + + assign sclk_div4_end = (cnt_sclk_div4 == c_sclk_div4_endcnt-1)? 1'b1 : 1'b0; + + // counting the 4 quarters of the sccb clk period + always @ (posedge rst, posedge clk) + begin + if (rst) + cnt_4sclk <= 0; + else begin + if (ready_aux) // if inactive, no count and start counting + cnt_4sclk <= 0; + else if (sclk_end) + cnt_4sclk <= 0; + else if (sclk_div4_end) + cnt_4sclk <= cnt_4sclk + 1'b1; + end + end + + assign sclk_end = (sclk_div4_end==1'b1 && cnt_4sclk == 4-1)? 1'b1 : 1'b0; + + // counting the 8 bits of each of the 3 phases + // counting down to keep track of the bits, the first is the bit 7 + // the last the bit 0 + always @ (posedge rst, posedge clk) + begin + if (rst) + cnt_8bits <= 3'b111; + else begin + // send_data active in any of the 3 phases (SEND_BYTE_ST) + if (send_data==1'b0) // if inactive, no count and start counting + cnt_8bits <= 3'b111; + else if (cnt_8bits_end) + cnt_8bits <= 3'b111; + else if (sclk_end) + cnt_8bits <= cnt_8bits - 1'b1; + end + end + + assign cnt_8bits_end = (sclk_end==1'b1 && cnt_8bits == 0)? 1'b1 : 1'b0; + + // counting the 3 phases of a SCCB write + always @ (posedge rst, posedge clk) + begin + if (rst) + cnt_phases <= 2'd0; + else begin + if (ready_aux) + cnt_phases <= 2'd0; + else if (phases_end) + cnt_phases <= 2'd0; + else if (new_phase) + cnt_phases <= cnt_phases + 1'b1; + end + end + + // 3 phases for writting + assign phases_end = (cnt_phases == 3-1 && new_phase ==1'b1) ? 1'b1 : 1'b0; + + // FSM sequential process + always @ (posedge rst, posedge clk) + begin + if (rst) + pr_sccb_st <= IDLE_ST; + else + pr_sccb_st <= nx_sccb_st; + end + + // FSM combinatorial process + always @ (pr_sccb_st or start_tx or cnt_4sclk or sclk_end or send_rg or + cnt_8bits or cnt_phases or cnt_8bits_end) + begin + // default values + ready_aux = 1'b0; // only ready in IDLE + sdat_on = 1'b0; + sdat_out = 1'b1; + nx_sccb_st = pr_sccb_st; + save_indata = 1'b0; + clr_datarg = 1'b0; + send_data = 1'b0; + new_phase = 1'b0; + //finish_tx = 1'b0; + // + sclk = 1'b1; + case (pr_sccb_st) + IDLE_ST: begin // waiting to send, not busy + ready_aux = 1'b1; // ready to send + sclk = 1'b1; + sdat_on = 1'b0; //Z + sdat_out = 1'b1; + if (start_tx) begin + nx_sccb_st = INIT_SEQ_ST; + save_indata = 1'b1; //id, address and data to write have to be saved + end + end + INIT_SEQ_ST: begin // sending the initial sequence + sclk = 1'b1; + sdat_on = 1'b1; + case (cnt_4sclk) + 2'b00 : begin + sclk = 1'b1; + sdat_out = 1'b1; + end + 2'b01, 2'b10 : begin + sclk = 1'b1; + sdat_out = 1'b0; + end + default : begin //3 + sclk = 1'b0; + sdat_out = 1'b0; + end + endcase + if (sclk_end) + nx_sccb_st = SEND_BYTE_ST; + end + SEND_BYTE_ST: begin // sending the bytes of any of the 3 phases + send_data = 1'b1; // enable the 8 bit counter + sdat_on = 1'b1; + case (cnt_4sclk) + 2'b00, 2'b11: + sclk = 1'b0; + default: //1, 2 + sclk = 1'b1; + endcase + sdat_out = send_rg[23]; + if (cnt_8bits_end) + nx_sccb_st = DNTC_ST; + end + DNTC_ST: begin // dont care bit, in i2c would be ack + sdat_on = 1'b0; // it will be Z + case (cnt_4sclk) + 2'b00, 2'b11: + sclk = 1'b0; + default: //1, 2 + sclk = 1'b1; + endcase + if (sclk_end) begin + new_phase = 1'b1; + if (cnt_phases == 3-1) + nx_sccb_st = END_SEQ_ST; // end of the transimission + else + nx_sccb_st = SEND_BYTE_ST; // new phase + end + end + END_SEQ_ST: begin // sending the end sequence + clr_datarg = 1'b1; //clear registers where the data to send is saved + sdat_on = 1'b1; + case (cnt_4sclk) + 2'b00: begin + sclk = 1'b0; + sdat_out = 1'b0; + end + 2'b01: begin + sclk = 1'b1; + sdat_out = 1'b0; + end + default: begin // 2 or 3 + sclk = 1'b1; + sdat_out = 1'b1; + end + endcase + if (sclk_end) begin + nx_sccb_st = IDLE_ST; + // finish_tx = 1'b1; // pulse to tell that transimission is done + end + end + endcase + end + +endmodule diff --git a/Projects/ComputerVision/xilinx_nexys4/ov7670_ObjectDetect/vga_display.v b/Projects/ComputerVision/xilinx_nexys4/ov7670_ObjectDetect/vga_display.v new file mode 100644 index 00000000..1d71bb1c --- /dev/null +++ b/Projects/ComputerVision/xilinx_nexys4/ov7670_ObjectDetect/vga_display.v @@ -0,0 +1,205 @@ +//------------------------------------------------------------------------------ +// Felipe Machado Sanchez +// Area de Tecnologia Electronica +// Universidad Rey Juan Carlos +// https://github.com/felipe-m +// +// vga_display.vhd +// Displays the image on the frambuffer to the VGA +// + +module vga_display + # (parameter + // VGA + //c_img_cols = 640, // 10 bits + //c_img_rows = 480, // 9 bits + //c_img_pxls = c_img_cols * c_img_rows, + //c_nb_line_pxls = 10, // log2i(c_img_cols-1) + 1; + // c_nb_img_pxls = log2i(c_img_pxls-1) + 1 + //c_nb_img_pxls = 19, //640*480=307,200 -> 2^19=524,288 + // QQVGA + //c_img_cols = 160, // 8 bits + //c_img_rows = 120, // 7 bits + //c_img_pxls = c_img_cols * c_img_rows, + //c_nb_img_pxls = 15, //160*120=19.200 -> 2^15 + // QQVGA /2 + c_img_cols = 80, // 7 bits + c_img_rows = 60, // 6 bits + c_img_pxls = c_img_cols * c_img_rows, + c_nb_img_pxls = 13, //80*60=4800 -> 2^13 + + + + c_nb_buf_red = 4, // n bits for red in the buffer (memory) + c_nb_buf_green = 4, // n bits for green in the buffer (memory) + c_nb_buf_blue = 4, // n bits for blue in the buffer (memory) + // word width of the memory (buffer) + c_nb_buf = c_nb_buf_red + c_nb_buf_green + c_nb_buf_blue + ) + ( + input rst, //reset, active high + input clk, //fpga cloc + input visible, + input new_pxl, + // input hsync, + // input vsync, + input rgbmode, + input testmode, + input [2:0] rgbfilter, + input [10-1:0] col, + input [10-1:0] row, + input [c_nb_buf-1:0] frame_pixel, + output reg [c_nb_img_pxls-1:0] frame_addr, + output reg [4-1:0] vga_red, + output reg [4-1:0] vga_green, + output reg [4-1:0] vga_blue + ); + + reg [7:0] char_rgbmode, char_testmode; + wire [2:0] char_row; + wire [2:0] char_col; + wire [3:0] addr_rom_rgb; + wire [3:0] addr_rom_test; + + assign char_row = row[2:0]; + assign char_col = col[2:0]; + assign addr_rom_rgb = {~rgbmode, char_row}; + assign addr_rom_test = {testmode, char_row}; + + always @ (addr_rom_rgb) begin + case (addr_rom_rgb) + 4'h0: char_rgbmode <= 8'b11111100; // R: RGB + 4'h1: char_rgbmode <= 8'b10000010; + 4'h2: char_rgbmode <= 8'b10000010; + 4'h3: char_rgbmode <= 8'b11111100; + 4'h4: char_rgbmode <= 8'b10001000; + 4'h5: char_rgbmode <= 8'b10000100; + 4'h6: char_rgbmode <= 8'b10000010; + 4'h7: char_rgbmode <= 8'b00000000; + 4'h8: char_rgbmode <= 8'b10000010; // Y: YUV + 4'h9: char_rgbmode <= 8'b01000100; + 4'hA: char_rgbmode <= 8'b00111000; + 4'hB: char_rgbmode <= 8'b00010000; + 4'hC: char_rgbmode <= 8'b00010000; + 4'hD: char_rgbmode <= 8'b00010000; + 4'hE: char_rgbmode <= 8'b00010000; + 4'hF: char_rgbmode <= 8'b00000000; + endcase + end + + always @ (addr_rom_test) begin + case (addr_rom_test) + 4'h0: char_testmode <= 8'b10000010; // N: Normal + 4'h1: char_testmode <= 8'b11000010; + 4'h2: char_testmode <= 8'b10100010; + 4'h3: char_testmode <= 8'b10010010; + 4'h4: char_testmode <= 8'b10001010; + 4'h5: char_testmode <= 8'b10000110; + 4'h6: char_testmode <= 8'b10000010; + 4'h7: char_testmode <= 8'b00000000; + 4'h8: char_testmode <= 8'b11111110; // T: Test + 4'h9: char_testmode <= 8'b00010000; + 4'hA: char_testmode <= 8'b00010000; + 4'hB: char_testmode <= 8'b00010000; + 4'hC: char_testmode <= 8'b00010000; + 4'hD: char_testmode <= 8'b00010000; + 4'hE: char_testmode <= 8'b00010000; + 4'hF: char_testmode <= 8'b00000000; + endcase + end + + + always @ (posedge rst, posedge clk) + begin + if (rst) + frame_addr <= 0; + else begin + if (row < c_img_rows) begin + if (col < c_img_cols) begin + if (new_pxl) + //it may have a simulation problem in the last pixel of the last row + frame_addr <= frame_addr + 1'b1; + end + end + else + frame_addr <= 0; + end + end + + + always @ (*) + begin + vga_red = 0; + vga_green = 0; + vga_blue = 0; + if (visible) begin + vga_red = {4{1'b0}}; + vga_green = {4{1'b0}}; + vga_blue = {4{1'b0}}; + if ((col < c_img_cols) && (row < c_img_rows)) begin + if (rgbmode) begin + vga_red = frame_pixel[c_nb_buf-1: c_nb_buf-c_nb_buf_red]; + vga_green = frame_pixel[c_nb_buf-c_nb_buf_red-1:c_nb_buf_blue]; + vga_blue = frame_pixel[c_nb_buf_blue-1:0]; + end + else begin + vga_red = frame_pixel[7:4]; + vga_green = frame_pixel[7:4]; + vga_blue = frame_pixel[7:4]; + end + end + else if ((col == c_img_cols) || (row == c_img_rows)) begin + vga_red = 4'b0000; + vga_green = 4'b1000; + vga_blue = 4'b1000; + end + else if ((col == 2*c_img_cols) || (row == 2*c_img_rows)) begin + vga_red = 4'b1000; + vga_green = 4'b1000; + vga_blue = 4'b0000; + end + else if ((col == 4*c_img_cols) || (row == 4*c_img_rows)) begin + vga_red = 4'b1000; + vga_green = 4'b0000; + vga_blue = 4'b1000; + end + else if ((row > 63) && (row < 64 + 8)) begin + if ((col > 7) && (col < 16)) begin // RGB MODE + if (char_rgbmode[7-char_col]) begin + vga_red = 4'b1111; + vga_green = 4'b1111; + vga_blue = 4'b1111; + end + else begin + vga_red = 4'b0000; + vga_green = 4'b0000; + vga_blue = 4'b0000; + end + end + else if ((col > 15) && (col < 24)) begin // TEST MODE + if (char_testmode[7-char_col]) begin + vga_red = 4'b1111; + vga_green = 4'b1111; + vga_blue = 4'b1111; + end + else begin + vga_red = 4'b0000; + vga_green = 4'b0000; + vga_blue = 4'b0000; + end + end + else if ((col > 23) && (col < 32)) begin // Color Filter + vga_red = {4{rgbfilter[2]}}; + vga_green = {4{rgbfilter[1]}}; + vga_blue = {4{rgbfilter[0]}}; + end + end + else begin + vga_red = 4'b0000; + vga_green = 4'b0000; + vga_blue = 4'b0000; + end + end + end + +endmodule diff --git a/Projects/ComputerVision/xilinx_nexys4/ov7670_ObjectDetect/vga_sync.v b/Projects/ComputerVision/xilinx_nexys4/ov7670_ObjectDetect/vga_sync.v new file mode 100644 index 00000000..70dcc22d --- /dev/null +++ b/Projects/ComputerVision/xilinx_nexys4/ov7670_ObjectDetect/vga_sync.v @@ -0,0 +1,179 @@ +//------------------------------------------------------------------------------ +// Felipe Machado Sanchez +// Departameto de Tecnologia Electronica +// Universidad Rey Juan Carlos +// https://github.com/felipe-m +// + +module vga_sync + #(parameter + c_pxl_visible = 640, + c_pxl_fporch = 16, + // from 0 to front porch + c_pxl_2_fporch = c_pxl_visible + c_pxl_fporch, // 656 + c_pxl_synch = 96, + // from 0 to synch + c_pxl_2_synch = c_pxl_2_fporch + c_pxl_synch, // 752 + // total horizontal pixels + c_pxl_total = 800, + // number of pixels of the backporch + c_pxl_bporch = c_pxl_total - c_pxl_2_synch, // 48 + // --------------- Number of rows (Vertical) ---------- + c_line_visible = 480, + c_line_fporch = 9, + // from 0 to front porch (vertical) + c_line_2_fporch = c_line_visible + c_line_fporch, // 489 + c_line_synch = 2, + // from init to synchro (vertical) + c_line_2_synch = c_line_2_fporch + c_line_synch, // 491 + // total number of lines + c_line_total = 520, + // number of lines of the back porch + c_line_bporch = c_line_total - c_line_2_synch, // 29 + + // number of bits for each count + c_nb_pxls = 10, //c_pxl_total : 800, + c_nb_lines = 10, //c_line_total : 520, + + // number of bits for each color RGB + c_nb_red = 4, + c_nb_green = 4, + c_nb_blue = 4, + + // VGA frequency + c_freq_vga = 25*10**6, // VGA 25MHz + + // active level of synchronization + c_synch_act = 0 + ) + ( + input rst, + input clk, + output visible, + output new_pxl, + output reg hsync, + output reg vsync, + output [10-1:0] col, + output [10-1:0] row + ); + + + reg [1:0] cnt_clk; // count 0 to 3: 4 clk cycles, from 100MHz to 15MHz + reg [10-1:0] cnt_pxl; + reg [10-1:0] cnt_line; + + wire end_cnt_pxl; + wire end_cnt_line; + wire new_line; + + reg visible_pxl; + reg visible_line; + + // count 4 clock cycles to get a pixel cycle + always @ (posedge rst, posedge clk) + begin + if (rst) + cnt_clk <= 2'd0; + else begin + if (new_pxl) + cnt_clk <= 2'd0; + else + cnt_clk <= cnt_clk + 1'b1; + end + end + + assign new_pxl = (cnt_clk==3) ? 1'b1 : 1'b0; + + assign col = cnt_pxl; + assign row = cnt_line; + assign visible = visible_pxl && visible_line; + + // counting 800 pixels (columns) + always @ (posedge rst, posedge clk) + begin + if (rst) + cnt_pxl <= 10'd0; + else begin + if (new_pxl) begin + if (end_cnt_pxl) + cnt_pxl <= 10'd0; + else + cnt_pxl <= cnt_pxl + 1'b1; + end + end + end + + // end of pixel count + assign end_cnt_pxl = (cnt_pxl == c_pxl_total-1) ? 1'b1 : 1'b0; + // nueva linea: cuando es el fin de cuenta y llega un nuevo pixel + assign new_line = end_cnt_pxl && new_pxl; + + // combinational outputs of pixel count (horizontal) + always @ (rst or cnt_pxl) + begin + if (rst) begin + visible_pxl = 1'b0; + hsync = ~c_synch_act; + end + else if (cnt_pxl < c_pxl_visible) begin + visible_pxl = 1'b1; + hsync = ~c_synch_act; + end + else if (cnt_pxl < c_pxl_2_fporch) begin + visible_pxl = 1'b0; + hsync = ~c_synch_act; + end + else if (cnt_pxl < c_pxl_2_synch) begin + visible_pxl = 1'b0; + hsync = c_synch_act; // synch active + end + else begin + visible_pxl = 1'b0; + hsync = ~c_synch_act; + end + end + + // counting 520 lines (rows) + always @ (posedge rst, posedge clk) + begin + if (rst) + cnt_line <= 10'd0; + else begin + if (new_line) begin + if (end_cnt_line) + cnt_line <= 10'd0; + else + cnt_line <= cnt_line + 1'b1; + end + end + end + + // end of pixel count + assign end_cnt_line = (cnt_line == c_line_total-1) ? 1'b1 : 1'b0; + + // combinational outputs of line count (vertical) + always @ (rst or cnt_line) + begin + if (rst) begin + visible_line = 1'b0; + vsync = ~c_synch_act; + end + else if (cnt_line < c_line_visible) begin + visible_line = 1'b1; + vsync = ~c_synch_act; + end + else if (cnt_line < c_line_2_fporch) begin + visible_line = 1'b0; + vsync = ~c_synch_act; + end + else if (cnt_line < c_line_2_synch) begin + visible_line = 1'b0; + vsync = c_synch_act; // synch active + end + else begin + visible_line = 1'b0; + vsync = ~c_synch_act; + end + end + +endmodule diff --git a/Projects/ComputerVision/xilinx_nexys4/readme.md b/Projects/ComputerVision/xilinx_nexys4/readme.md index 0cd602e5..75e3830e 100644 --- a/Projects/ComputerVision/xilinx_nexys4/readme.md +++ b/Projects/ComputerVision/xilinx_nexys4/readme.md @@ -28,4 +28,14 @@ Same as ULX3S version, but for Nexys4DDR There is the regs folder in which has the 2 versions of the OV7670 registers. The original one, and the one copied from the linux driver: -https://github.com/yandex/smart/blob/master/drivers/media/i2c/ov7670.c \ No newline at end of file +https://github.com/yandex/smart/blob/master/drivers/media/i2c/ov7670.c + +## ov7670_ObjectDetect + +Same as Alhambra II version, but for Nexys4DDR. + +As there are more pins available on the Nexys 4 all the data pins of the OV7670 camera will be used. + +The Nexys4DDR board has twice as many LEDs as the Alhambra II, therefore, it will have twice the precision to locate the object's centroid. + +![OV7670 camera and Nexys4DDR pin connection](https://github.com/JdeRobot/FPGA-robotics/blob/javi_garci/Projects/ComputerVision/xilinx_nexys4/ov7670_ObjectDetect/OV7670_Nexys_interface.png)